• .NETCORE 微软企业登录


    1.常用类如下

    Samlv1ClaimsTransform.cs

    1. public static class Samlv1ClaimsTransform
    2. {
    3. public static ClaimsPrincipal Transform(ClaimsPrincipal incomingPrincipal)
    4. {
    5. if (!incomingPrincipal.Identity.IsAuthenticated)
    6. {
    7. return incomingPrincipal;
    8. }
    9. return CreateClaimsPrincipal(incomingPrincipal);
    10. }
    11. private static ClaimsPrincipal CreateClaimsPrincipal(ClaimsPrincipal incomingPrincipal)
    12. {
    13. var claims = new List();
    14. // All claims
    15. claims.AddRange(incomingPrincipal.Claims);
    16. // Or custom claims
    17. //claims.AddRange(GetSaml2LogoutClaims(incomingPrincipal));
    18. //claims.Add(new Claim(ClaimTypes.NameIdentifier, GetClaimValue(incomingPrincipal, ClaimTypes.NameIdentifier)));
    19. return new ClaimsPrincipal(new ClaimsIdentity(claims, incomingPrincipal.Identity.AuthenticationType, ClaimTypes.NameIdentifier, ClaimTypes.Role)
    20. {
    21. BootstrapContext = ((ClaimsIdentity)incomingPrincipal.Identity).BootstrapContext
    22. });
    23. }
    24. private static IEnumerable GetSaml2LogoutClaims(ClaimsPrincipal principal)
    25. {
    26. yield return GetClaim(principal, Saml2ClaimTypes.NameId);
    27. yield return GetClaim(principal, Saml2ClaimTypes.NameIdFormat);
    28. yield return GetClaim(principal, Saml2ClaimTypes.SessionIndex);
    29. }
    30. private static Claim GetClaim(ClaimsPrincipal principal, string claimType)
    31. {
    32. return ((ClaimsIdentity)principal.Identity).Claims.Where(c => c.Type == claimType).FirstOrDefault();
    33. }
    34. private static string GetClaimValue(ClaimsPrincipal principal, string claimType)
    35. {
    36. var claim = GetClaim(principal, claimType);
    37. return claim != null ? claim.Value : null;
    38. }
    39. }

    Samlv2AuthRequest.cs

    1. public class Samlv2AuthRequest
    2. {
    3. public string _id;
    4. private string _issue_instant;
    5. private string _issuer;
    6. private string _assertionConsumerServiceUrl;
    7. public enum AuthRequestFormat
    8. {
    9. Base64 = 1
    10. }
    11. public Samlv2AuthRequest(string issuer, string assertionConsumerServiceUrl)
    12. {
    13. _id = "_" + Guid.NewGuid().ToString();
    14. _issue_instant = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ", System.Globalization.CultureInfo.InvariantCulture);
    15. _issuer = issuer;
    16. _assertionConsumerServiceUrl = assertionConsumerServiceUrl;
    17. }
    18. public string GetRequest(AuthRequestFormat format)
    19. {
    20. using (StringWriter sw = new StringWriter())
    21. {
    22. XmlWriterSettings xws = new XmlWriterSettings();
    23. xws.OmitXmlDeclaration = true;
    24. using (XmlWriter xw = XmlWriter.Create(sw, xws))
    25. {
    26. xw.WriteStartElement("samlp", "AuthnRequest", "urn:oasis:names:tc:SAML:2.0:protocol");
    27. xw.WriteAttributeString("ID", _id);
    28. xw.WriteAttributeString("Version", "2.0");
    29. xw.WriteAttributeString("IssueInstant", _issue_instant);
    30. xw.WriteAttributeString("ProtocolBinding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
    31. xw.WriteAttributeString("AssertionConsumerServiceURL", _assertionConsumerServiceUrl);
    32. xw.WriteStartElement("saml", "Issuer", "urn:oasis:names:tc:SAML:2.0:assertion");
    33. xw.WriteString(_issuer);
    34. xw.WriteEndElement();
    35. xw.WriteStartElement("samlp", "NameIDPolicy", "urn:oasis:names:tc:SAML:2.0:protocol");
    36. xw.WriteAttributeString("Format", "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");
    37. xw.WriteAttributeString("AllowCreate", "true");
    38. xw.WriteEndElement();
    39. /*xw.WriteStartElement("samlp", "RequestedAuthnContext", "urn:oasis:names:tc:SAML:2.0:protocol");
    40. xw.WriteAttributeString("Comparison", "exact");
    41. xw.WriteStartElement("saml", "AuthnContextClassRef", "urn:oasis:names:tc:SAML:2.0:assertion");
    42. xw.WriteString("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport");
    43. xw.WriteEndElement();
    44. xw.WriteEndElement();*/
    45. xw.WriteEndElement();
    46. }
    47. if (format == AuthRequestFormat.Base64)
    48. {
    49. //byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(sw.ToString());
    50. //return System.Convert.ToBase64String(toEncodeAsBytes);
    51. //https://stackoverflow.com/questions/25120025/acs75005-the-request-is-not-a-valid-saml2-protocol-message-is-showing-always%3C/a%3E
    52. var memoryStream = new MemoryStream();
    53. var writer = new StreamWriter(new DeflateStream(memoryStream, CompressionMode.Compress, true), new UTF8Encoding(false));
    54. writer.Write(sw.ToString());
    55. writer.Close();
    56. string result = Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length, Base64FormattingOptions.None);
    57. return result;
    58. }
    59. return null;
    60. }
    61. }
    62. //returns the URL you should redirect your users to (i.e. your SAML-provider login URL with the Base64-ed request in the querystring
    63. public string GetRedirectUrl(string samlEndpoint, string relayState = null)
    64. {
    65. var queryStringSeparator = samlEndpoint.Contains("?") ? "&" : "?";
    66. var url = samlEndpoint + queryStringSeparator + "SAMLRequest=" + Uri.EscapeDataString(GetRequest(AuthRequestFormat.Base64));
    67. if (!string.IsNullOrEmpty(relayState))
    68. {
    69. url += "&RelayState=" + Uri.EscapeDataString(relayState);
    70. }
    71. return url;
    72. }
    73. }

    Samlv2Response.cs

    1. public class Samlv2Response
    2. {
    3. private static byte[] StringToByteArray(string st)
    4. {
    5. byte[] bytes = new byte[st.Length];
    6. for (int i = 0; i < st.Length; i++)
    7. {
    8. bytes[i] = (byte)st[i];
    9. }
    10. return bytes;
    11. }
    12. protected XmlDocument _xmlDoc;
    13. protected readonly X509Certificate2 _certificate;
    14. protected XmlNamespaceManager _xmlNameSpaceManager; //we need this one to run our XPath queries on the SAML XML
    15. public string Xml { get { return _xmlDoc.OuterXml; } }
    16. public Samlv2Response(string certificateStr, string responseString)
    17. : this(StringToByteArray(certificateStr), responseString) { }
    18. public Samlv2Response(byte[] certificateBytes, string responseString) : this(certificateBytes)
    19. {
    20. LoadXmlFromBase64(responseString);
    21. }
    22. public Samlv2Response(string certificateStr) : this(StringToByteArray(certificateStr)) { }
    23. public Samlv2Response(byte[] certificateBytes)
    24. {
    25. _certificate = new X509Certificate2(certificateBytes);
    26. }
    27. public void LoadXml(string xml)
    28. {
    29. _xmlDoc = new XmlDocument();
    30. _xmlDoc.PreserveWhitespace = true;
    31. _xmlDoc.XmlResolver = null;
    32. _xmlDoc.LoadXml(xml);
    33. _xmlNameSpaceManager = GetNamespaceManager(); //lets construct a "manager" for XPath queries
    34. }
    35. public void LoadXmlFromBase64(string response)
    36. {
    37. UTF8Encoding enc = new UTF8Encoding();
    38. LoadXml(enc.GetString(Convert.FromBase64String(response)));
    39. }
    40. public bool IsValid()
    41. {
    42. XmlNodeList nodeList = _xmlDoc.SelectNodes("//ds:Signature", _xmlNameSpaceManager);
    43. SignedXml signedXml = new SignedXml(_xmlDoc);
    44. if (nodeList.Count == 0) return false;
    45. signedXml.LoadXml((XmlElement)nodeList[0]);
    46. return ValidateSignatureReference(signedXml) && signedXml.CheckSignature(_certificate, true) && !IsExpired();
    47. }
    48. public string GetSamlXmlResponse()
    49. {
    50. return _xmlDoc.InnerXml;
    51. }
    52. //an XML signature can "cover" not the whole document, but only a part of it
    53. //.NET's built in "CheckSignature" does not cover this case, it will validate to true.
    54. //We should check the signature reference, so it "references" the id of the root document element! If not - it's a hack
    55. private bool ValidateSignatureReference(SignedXml signedXml)
    56. {
    57. if (signedXml.SignedInfo.References.Count != 1) //no ref at all
    58. return false;
    59. var reference = (Reference)signedXml.SignedInfo.References[0];
    60. var id = reference.Uri.Substring(1);
    61. var idElement = signedXml.GetIdElement(_xmlDoc, id);
    62. if (idElement == _xmlDoc.DocumentElement)
    63. return true;
    64. else //sometimes its not the "root" doc-element that is being signed, but the "assertion" element
    65. {
    66. var assertionNode = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion", _xmlNameSpaceManager) as XmlElement;
    67. if (assertionNode != idElement)
    68. return false;
    69. }
    70. return true;
    71. }
    72. private bool IsExpired()
    73. {
    74. DateTime expirationDate = DateTime.MaxValue;
    75. XmlNode node = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion[1]/saml:Subject/saml:SubjectConfirmation/saml:SubjectConfirmationData", _xmlNameSpaceManager);
    76. if (node != null && node.Attributes["NotOnOrAfter"] != null)
    77. {
    78. DateTime.TryParse(node.Attributes["NotOnOrAfter"].Value, out expirationDate);
    79. }
    80. return DateTime.UtcNow > expirationDate.ToUniversalTime();
    81. }
    82. public string GetNameID()
    83. {
    84. XmlNode node = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion[1]/saml:Subject/saml:NameID", _xmlNameSpaceManager);
    85. return node.InnerText;
    86. }
    87. public string GetUserID()
    88. {
    89. return GetCustomAttribute("http://schemas.microsoft.com/identity/claims/objectidentifier");
    90. }
    91. public string GetRoles()
    92. {
    93. return GetCustomAttribute("User.roles")
    94. ?? 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"
    95. ?? GetCustomAttribute("roles"); //some providers put last name into an attribute named "mail"
    96. }
    97. public virtual string GetUpn()
    98. {
    99. return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn");
    100. }
    101. public virtual string GetEmail()
    102. {
    103. return GetCustomAttribute("User.email")
    104. ?? 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"
    105. ?? GetCustomAttribute("mail"); //some providers put last name into an attribute named "mail"
    106. }
    107. public virtual string GetFirstName()
    108. {
    109. return GetCustomAttribute("first_name")
    110. ?? 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"
    111. ?? GetCustomAttribute("User.FirstName")
    112. ?? GetCustomAttribute("givenName"); //some providers put last name into an attribute named "givenName"
    113. }
    114. public virtual string GetLastName()
    115. {
    116. return GetCustomAttribute("last_name")
    117. ?? 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"
    118. ?? GetCustomAttribute("User.LastName")
    119. ?? GetCustomAttribute("sn"); //some providers put last name into an attribute named "sn"
    120. }
    121. public virtual string GetDepartment()
    122. {
    123. return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/department")
    124. ?? GetCustomAttribute("department");
    125. }
    126. public virtual string GetPhone()
    127. {
    128. return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/homephone")
    129. ?? GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/telephonenumber");
    130. }
    131. public virtual string GetCompany()
    132. {
    133. return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/companyname")
    134. ?? GetCustomAttribute("organization")
    135. ?? GetCustomAttribute("User.CompanyName");
    136. }
    137. public virtual string GetLocation()
    138. {
    139. return GetCustomAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/location")
    140. ?? GetCustomAttribute("physicalDeliveryOfficeName");
    141. }
    142. public string GetCustomAttribute(string attr)
    143. {
    144. XmlNode node = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion[1]/saml:AttributeStatement/saml:Attribute[@Name='" + attr + "']/saml:AttributeValue", _xmlNameSpaceManager);
    145. return node == null ? null : node.InnerText;
    146. }
    147. //returns namespace manager, we need one b/c MS says so... Otherwise XPath doesnt work in an XML doc with namespaces
    148. //see https://stackoverflow.com/questions/7178111/why-is-xmlnamespacemanager-necessary
    149. private XmlNamespaceManager GetNamespaceManager()
    150. {
    151. XmlNamespaceManager manager = new XmlNamespaceManager(_xmlDoc.NameTable);
    152. manager.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
    153. manager.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion");
    154. manager.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol");
    155. return manager;
    156. }
    157. }

    2.控制器调用

    1. //根据企业码查看当前的企业码是否存在,然后并且返回跳转数据
    2. [Route("sso/ssologin")]
    3. [HttpGet]
    4. public async Task> SsoLogin(string CorporateCode)
    5. {
    6. if (!string.IsNullOrEmpty(CorporateCode))
    7. {
    8. //查询企业码是否存在
    9. var result = await ——**.GetSpIdp(CorporateCode, "", "", "");
    10. if (result.Rows.Count == 0)
    11. {
    12. return ApiResultHelper.renderError("CorporateCode is null ");
    13. }
    14. if (result.Rows[0]["isena**"].ToString() == "0")
    15. {
    16. return ApiResultHelper.renderError("CorporateCode is null ");
    17. }
    18. var samlEndpoint = result.Rows[0]["idpsso**"].ToString();
    19. var sp_consumer_url = result.Rows[0]["spconsum**"].ToString();
    20. var request = new Samlv2AuthRequest(
    21. "****", //TODO: put your app's "entity ID" here urn:auth0:YOUR_TENANT:YOUR_CONNECTION_NAME
    22. sp_consumer_url //TODO: put Assertion Consumer URL (where the provider should redirect users after authenticating)
    23. );
    24. //redirect the user to the SAML provider
    25. return ApiResultHelper.renderSuccess(request.GetRedirectUrl(samlEndpoint), "success!");//, "https://www.corriere.it/"
    26. }
    27. return ApiResultHelper.renderError("CorporateCode is null ");
    28. }
    1. [Route("**/**/**/{param1}/{param2}")]
    2. [HttpPost]
    3. //ASP.NET MVC action method... But you can easily modify the code for Web-forms etc.
    4. public async Task> Samlv2Consumer(string param1, string param2)
    5. {
    6. var url = "";
    7. var result = await ——**.GetSpIdp("", "", param2, param1);
    8. if (result.Rows.Count == 0)
    9. {
    10. return ApiResultHelper.renderError("request is fail");
    11. }
    12. // 1. TODO: specify the certificate that your SAML provider gave you
    13. string samlCertificate = result.Rows[0]["idp_certificate"].ToString();
    14. // string samlCertificate = ByFingerpritntGetBase64("**");
    15. // 2. Let's read the data - SAML providers usually POST it into the "SAMLResponse" var
    16. var samlResponse = new Samlv2Response(samlCertificate, Request.Form["SAMLResponse"]);
    17. //for log purpose
    18. var samlTextResponse = samlResponse.GetSamlXmlResponse();
    19. Dictionary<string, string> dic = new Dictionary<string, string>();
    20. // 3. We're done!
    21. if (samlResponse.IsValid())
    22. {
    23. //WOOHOO!!! user is logged in
    24. //Some more optional stuff for you
    25. //let's extract username/firstname etc
    26. string username, email, firstname, lastname, userid;
    27. try
    28. {
    29. userid = samlResponse.GetUserID();
    30. username = samlResponse.GetNameID();
    31. email = samlResponse.GetEmail();
    32. firstname = samlResponse.GetFirstName();
    33. lastname = samlResponse.GetLastName();
    34. /*删除部分代码*/
    35. url = Appsettings.GetNode("**") + "error";
    36. return Redirect(url);
    37. }
    38. catch (Exception ex)
    39. {
    40. //insert error handling code
    41. //no, really, please do
    42. return ApiResultHelper.renderError(ex.Message);
    43. }
    44. //user has been authenticated, put your code here, like set a cookie or something...
    45. //or call FormsAuthentication.SetAuthCookie()
    46. //or call context.SignInAsync() in ASP.NET Core
    47. //or do something else
    48. }
    49. return ApiResultHelper.renderError(false);
    50. }

  • 相关阅读:
    Linux用户空间与内核空间通信(Netlink通信机制)
    文件工具类
    Java String.valueOf()方法具有什么功能呢?
    Maven工程开发
    大屏可视化!2022新趋势!
    【chat】3: ubutnu 安装mysql-8
    图解Vit 2:Vision Transformer——视觉问题中的注意力机制
    HTML入门(详细)
    Go 通道机制与应用详解
    Abnormal build process termination:错误解决
  • 原文地址:https://blog.csdn.net/qq_36694046/article/details/139677667