.NETCORE 微软企业登录

ops/2024/10/18 12:20:44/

1.常用类如下

Samlv1ClaimsTransform.cs

public static class Samlv1ClaimsTransform
{public static ClaimsPrincipal Transform(ClaimsPrincipal incomingPrincipal){if (!incomingPrincipal.Identity.IsAuthenticated){return incomingPrincipal;}return CreateClaimsPrincipal(incomingPrincipal);}private static ClaimsPrincipal CreateClaimsPrincipal(ClaimsPrincipal incomingPrincipal){var claims = new List<Claim>();// All claimsclaims.AddRange(incomingPrincipal.Claims);// Or custom claims//claims.AddRange(GetSaml2LogoutClaims(incomingPrincipal));//claims.Add(new Claim(ClaimTypes.NameIdentifier, GetClaimValue(incomingPrincipal, ClaimTypes.NameIdentifier)));return new ClaimsPrincipal(new ClaimsIdentity(claims, incomingPrincipal.Identity.AuthenticationType, ClaimTypes.NameIdentifier, ClaimTypes.Role){BootstrapContext = ((ClaimsIdentity)incomingPrincipal.Identity).BootstrapContext});}private static IEnumerable<Claim> GetSaml2LogoutClaims(ClaimsPrincipal principal){yield return GetClaim(principal, Saml2ClaimTypes.NameId);yield return GetClaim(principal, Saml2ClaimTypes.NameIdFormat);yield return GetClaim(principal, Saml2ClaimTypes.SessionIndex);}private static Claim GetClaim(ClaimsPrincipal principal, string claimType){return ((ClaimsIdentity)principal.Identity).Claims.Where(c => c.Type == claimType).FirstOrDefault();}private static string GetClaimValue(ClaimsPrincipal principal, string claimType){var claim = GetClaim(principal, claimType);return claim != null ? claim.Value : null;}
}

Samlv2AuthRequest.cs

public class Samlv2AuthRequest
{public string _id;private string _issue_instant;private string _issuer;private string _assertionConsumerServiceUrl;public enum AuthRequestFormat{Base64 = 1}public Samlv2AuthRequest(string issuer, string assertionConsumerServiceUrl){_id = "_" + Guid.NewGuid().ToString();_issue_instant = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ", System.Globalization.CultureInfo.InvariantCulture);_issuer = issuer;_assertionConsumerServiceUrl = assertionConsumerServiceUrl;}public string GetRequest(AuthRequestFormat format){using (StringWriter sw = new StringWriter()){XmlWriterSettings xws = new XmlWriterSettings();xws.OmitXmlDeclaration = true;using (XmlWriter xw = XmlWriter.Create(sw, xws)){xw.WriteStartElement("samlp", "AuthnRequest", "urn:oasis:names:tc:SAML:2.0:protocol");xw.WriteAttributeString("ID", _id);xw.WriteAttributeString("Version", "2.0");xw.WriteAttributeString("IssueInstant", _issue_instant);xw.WriteAttributeString("ProtocolBinding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");xw.WriteAttributeString("AssertionConsumerServiceURL", _assertionConsumerServiceUrl);xw.WriteStartElement("saml", "Issuer", "urn:oasis:names:tc:SAML:2.0:assertion");xw.WriteString(_issuer);xw.WriteEndElement();xw.WriteStartElement("samlp", "NameIDPolicy", "urn:oasis:names:tc:SAML:2.0:protocol");xw.WriteAttributeString("Format", "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");xw.WriteAttributeString("AllowCreate", "true");xw.WriteEndElement();/*xw.WriteStartElement("samlp", "RequestedAuthnContext", "urn:oasis:names:tc:SAML:2.0:protocol");xw.WriteAttributeString("Comparison", "exact");xw.WriteStartElement("saml", "AuthnContextClassRef", "urn:oasis:names:tc:SAML:2.0:assertion");xw.WriteString("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport");xw.WriteEndElement();xw.WriteEndElement();*/xw.WriteEndElement();}if (format == AuthRequestFormat.Base64){//byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(sw.ToString());//return System.Convert.ToBase64String(toEncodeAsBytes);//https://stackoverflow.com/questions/25120025/acs75005-the-request-is-not-a-valid-saml2-protocol-message-is-showing-always%3C/a%3Evar memoryStream = new MemoryStream();var writer = new StreamWriter(new DeflateStream(memoryStream, CompressionMode.Compress, true), new UTF8Encoding(false));writer.Write(sw.ToString());writer.Close();string result = Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length, Base64FormattingOptions.None);return result;}return null;}}//returns the URL you should redirect your users to (i.e. your SAML-provider login URL with the Base64-ed request in the querystringpublic string GetRedirectUrl(string samlEndpoint, string relayState = null){var queryStringSeparator = samlEndpoint.Contains("?") ? "&" : "?";var url = samlEndpoint + queryStringSeparator + "SAMLRequest=" + Uri.EscapeDataString(GetRequest(AuthRequestFormat.Base64));if (!string.IsNullOrEmpty(relayState)){url += "&RelayState=" + Uri.EscapeDataString(relayState);}return url;}
}

Samlv2Response.cs

 public class Samlv2Response{private static byte[] StringToByteArray(string st){byte[] bytes = new byte[st.Length];for (int i = 0; i < st.Length; i++){bytes[i] = (byte)st[i];}return bytes;}protected XmlDocument _xmlDoc;protected readonly X509Certificate2 _certificate;protected XmlNamespaceManager _xmlNameSpaceManager; //we need this one to run our XPath queries on the SAML XMLpublic string Xml { get { return _xmlDoc.OuterXml; } }public Samlv2Response(string certificateStr, string responseString): this(StringToByteArray(certificateStr), responseString) { }public Samlv2Response(byte[] certificateBytes, string responseString) : this(certificateBytes){LoadXmlFromBase64(responseString);}public Samlv2Response(string certificateStr) : this(StringToByteArray(certificateStr)) { }public Samlv2Response(byte[] certificateBytes){_certificate = new X509Certificate2(certificateBytes);}public void LoadXml(string xml){_xmlDoc = new XmlDocument();_xmlDoc.PreserveWhitespace = true;_xmlDoc.XmlResolver = null;_xmlDoc.LoadXml(xml);_xmlNameSpaceManager = GetNamespaceManager(); //lets construct a "manager" for XPath queries}public void LoadXmlFromBase64(string response){UTF8Encoding enc = new UTF8Encoding();LoadXml(enc.GetString(Convert.FromBase64String(response)));}public bool IsValid(){XmlNodeList nodeList = _xmlDoc.SelectNodes("//ds:Signature", _xmlNameSpaceManager);SignedXml signedXml = new SignedXml(_xmlDoc);if (nodeList.Count == 0) return false;signedXml.LoadXml((XmlElement)nodeList[0]);return ValidateSignatureReference(signedXml) && signedXml.CheckSignature(_certificate, true) && !IsExpired();}public string GetSamlXmlResponse(){return _xmlDoc.InnerXml;}//an XML signature can "cover" not the whole document, but only a part of it//.NET's built in "CheckSignature" does not cover this case, it will validate to true.//We should check the signature reference, so it "references" the id of the root document element! If not - it's a hackprivate bool ValidateSignatureReference(SignedXml signedXml){if (signedXml.SignedInfo.References.Count != 1) //no ref at allreturn false;var reference = (Reference)signedXml.SignedInfo.References[0];var id = reference.Uri.Substring(1);var idElement = signedXml.GetIdElement(_xmlDoc, id);if (idElement == _xmlDoc.DocumentElement)return true;else //sometimes its not the "root" doc-element that is being signed, but the "assertion" element{var assertionNode = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion", _xmlNameSpaceManager) as XmlElement;if (assertionNode != idElement)return false;}return true;}private bool IsExpired(){DateTime expirationDate = DateTime.MaxValue;XmlNode node = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion[1]/saml:Subject/saml:SubjectConfirmation/saml:SubjectConfirmationData", _xmlNameSpaceManager);if (node != null && node.Attributes["NotOnOrAfter"] != null){DateTime.TryParse(node.Attributes["NotOnOrAfter"].Value, out expirationDate);}return DateTime.UtcNow > expirationDate.ToUniversalTime();}public string GetNameID(){XmlNode node = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion[1]/saml:Subject/saml:NameID", _xmlNameSpaceManager);return node.InnerText;}public string GetUserID(){return GetCustomAttribute("http://schemas.microsoft.com/identity/claims/objectidentifier");}public string GetRoles(){return GetCustomAttribute("User.roles")?? GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/roles") //some providers (for example Azure AD) put last name into an attribute named "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"?? GetCustomAttribute("roles"); //some providers put last name into an attribute named "mail"}public virtual string GetUpn(){return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn");}public virtual string GetEmail(){return GetCustomAttribute("User.email")?? GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress") //some providers (for example Azure AD) put last name into an attribute named "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"?? GetCustomAttribute("mail"); //some providers put last name into an attribute named "mail"}public virtual string GetFirstName(){return GetCustomAttribute("first_name")?? GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname") //some providers (for example Azure AD) put last name into an attribute named "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"?? GetCustomAttribute("User.FirstName")?? GetCustomAttribute("givenName"); //some providers put last name into an attribute named "givenName"}public virtual string GetLastName(){return GetCustomAttribute("last_name")?? GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname") //some providers (for example Azure AD) put last name into an attribute named "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"?? GetCustomAttribute("User.LastName")?? GetCustomAttribute("sn"); //some providers put last name into an attribute named "sn"}public virtual string GetDepartment(){return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/department")?? GetCustomAttribute("department");}public virtual string GetPhone(){return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/homephone")?? GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/telephonenumber");}public virtual string GetCompany(){return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/companyname")?? GetCustomAttribute("organization")?? GetCustomAttribute("User.CompanyName");}public virtual string GetLocation(){return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/location")?? GetCustomAttribute("physicalDeliveryOfficeName");}public string GetCustomAttribute(string attr){XmlNode node = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion[1]/saml:AttributeStatement/saml:Attribute[@Name='" + attr + "']/saml:AttributeValue", _xmlNameSpaceManager);return node == null ? null : node.InnerText;}//returns namespace manager, we need one b/c MS says so... Otherwise XPath doesnt work in an XML doc with namespaces//see https://stackoverflow.com/questions/7178111/why-is-xmlnamespacemanager-necessaryprivate XmlNamespaceManager GetNamespaceManager(){XmlNamespaceManager manager = new XmlNamespaceManager(_xmlDoc.NameTable);manager.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);manager.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion");manager.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol");return manager;}}

2.控制器调用

//根据企业码查看当前的企业码是否存在,然后并且返回跳转数据
[Route("sso/ssologin")]
[HttpGet]
public async Task<ActionResult<Result>> SsoLogin(string CorporateCode)
{if (!string.IsNullOrEmpty(CorporateCode)){//查询企业码是否存在var result = await ——**.GetSpIdp(CorporateCode, "", "", "");if (result.Rows.Count == 0){return ApiResultHelper.renderError("CorporateCode is null ");}if (result.Rows[0]["isena**"].ToString() == "0"){return ApiResultHelper.renderError("CorporateCode is null ");}var samlEndpoint = result.Rows[0]["idpsso**"].ToString();var sp_consumer_url = result.Rows[0]["spconsum**"].ToString();var request = new Samlv2AuthRequest("****", //TODO: put your app's "entity ID" here urn:auth0:YOUR_TENANT:YOUR_CONNECTION_NAMEsp_consumer_url //TODO: put Assertion Consumer URL (where the provider should redirect users after authenticating));//redirect the user to the SAML providerreturn ApiResultHelper.renderSuccess(request.GetRedirectUrl(samlEndpoint), "success!");//, "https://www.corriere.it/"}return ApiResultHelper.renderError("CorporateCode is null ");
}

[Route("**/**/**/{param1}/{param2}")]
[HttpPost]
//ASP.NET MVC action method... But you can easily modify the code for Web-forms etc.
public async Task<ActionResult<Result>> Samlv2Consumer(string param1, string param2)
{var url = "";var result = await ——**.GetSpIdp("", "", param2, param1);if (result.Rows.Count == 0){return ApiResultHelper.renderError("request is fail");}// 1. TODO: specify the certificate that your SAML provider gave youstring samlCertificate = result.Rows[0]["idp_certificate"].ToString();// string samlCertificate = ByFingerpritntGetBase64("**");// 2. Let's read the data - SAML providers usually POST it into the "SAMLResponse" varvar samlResponse = new Samlv2Response(samlCertificate, Request.Form["SAMLResponse"]);//for log purposevar samlTextResponse = samlResponse.GetSamlXmlResponse();Dictionary<string, string> dic = new Dictionary<string, string>();// 3. We're done!if (samlResponse.IsValid()){//WOOHOO!!! user is logged in//Some more optional stuff for you//let's extract username/firstname etcstring username, email, firstname, lastname, userid;try{userid = samlResponse.GetUserID();username = samlResponse.GetNameID();email = samlResponse.GetEmail();firstname = samlResponse.GetFirstName();lastname = samlResponse.GetLastName();/*删除部分代码*/url = Appsettings.GetNode("**") + "error";return Redirect(url);}catch (Exception ex){//insert error handling code//no, really, please doreturn ApiResultHelper.renderError(ex.Message);}//user has been authenticated, put your code here, like set a cookie or something...//or call FormsAuthentication.SetAuthCookie()//or call context.SignInAsync() in ASP.NET Core//or do something else}return ApiResultHelper.renderError(false);
}


http://www.ppmy.cn/ops/50034.html

相关文章

【html5的video标签在移动端的使用】【微信内部浏览器video自动播放】【vue-video-player】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、使用步骤1. html部分2.js部分 二、使用插件vue-video-player1、下载插件2、使用3、在组件中使用 三、video相关文章推荐 前言 在移动端的首页用视频做背景…

果园预售系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;果树管理&#xff0c;果园管理&#xff0c;果园预约管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;论坛&#xff0c;公告&a…

Mysql 的分布式策略

1. 前言 MySQL 作为最最常用的数据库&#xff0c;了解 Mysql 的分布式策略对于掌握 MySQL 的高性能使用方法和更安全的储存方式有非常重要的作用。 它同时也是面试中最最常问的考点&#xff0c;我们这里就简单总结下 Mysq 的常用分布式策略。 2. 复制 复制主要有主主复制和…

描述React中的函数组件和类组件之间的区别

React中的函数组件和类组件之间存在显著的区别&#xff0c;以下是对这些区别的详细描述&#xff1a; 语法与设计思想&#xff1a; 函数组件&#xff1a;采用函数式编程思想&#xff0c;使用纯JavaScript函数定义。函数组件接收一个输入参数props&#xff0c;并返回一个React元…

四川古力未来科技抖音小店打造品质生活,可靠之选引领潮流

在当今数字化快速发展的时代&#xff0c;电商平台如雨后春笋般涌现&#xff0c;抖音小店作为其中的佼佼者&#xff0c;凭借其独特的短视频电商模式&#xff0c;迅速吸引了大批年轻消费者的目光。而在众多的抖音小店中&#xff0c;四川古力未来科技抖音小店凭借其卓越的品质和专…

SylixOS下UDP组播测试程序

SylixOS下UDP组播测试 测试效果截图如下: udp组播发送测试程序。 /********************************************************************************************************* ** ** 中国软件开源组织 ** ** …

专业媒体公关-北京-上海-60城媒体邀约服务机构-51媒体网

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 「51媒体」提供的媒体邀约服务致力于帮助企业或机构邀请全国范围内的媒体进行现场报道宣传。 媒体邀约的重要性 媒体邀约是一种有效的宣传手段&#xff0c;可以帮助企业或活动在公众中…

图神经网络实战(14)——基于节点嵌入预测链接

图神经网络实战&#xff08;14&#xff09;——基于节点嵌入预测链接 0. 前言1. 图自编码器2. 变分图自编码器3. 实现变分图自编码器小结系列链接 0. 前言 我们已经了解了如何使用图神经网络 (Graph Neural Networks, GNN) 生成节点嵌入&#xff0c;我们可以使用这些嵌入执行矩…