基于SAML2.0的SSO实现(C#&Java)

发布时间 2023-11-01 20:47:16作者: talentzemin

背景

如题

原理

和对接其他平台一样,在开始之前我们要向调用的服务方申请一些东西,以便后面开展工作,比如,下图就是微信公众平台开发时候需要进行的操作:

我们的开发也是一样,也需要这样的前期准备。
这个过程可能是通过线上填写信息,也可能发个邮件加个附件,也可以是线下找对应的人员沟通。
总之,目的就是:交换信息。

交换信息的目的就是后面流程使用

准备

我所在的项目是通过发送XML文件给IdP的IT管理人员,长这样:

<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor ID="" entityID="sp.cnblogs.com" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
    <md:SPSSODescriptor AuthnRequestsSigned="false" ID="" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <md:KeyDescriptor use="signing">
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>####</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:KeyDescriptor use="encryption">
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>####</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                                     Location="https://sp.cnblogs.com/sso/acs"
                                     index="0" isDefault="true"/>
        <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
                                     Location="https://sp.cnblogs.com/sso/acs"
                                     index="1" isDefault="false"/>
    </md:SPSSODescriptor>
</md:EntityDescriptor>

然后对方给了我这样一个XML,这里面主要有IdP的Login URL和证书信息。

<md:EntityDescriptor ID="" cacheDuration="" entityID="sso.cnblogs.com"
    xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
    <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"
        WantAuthnRequestsSigned="false">
        <md:KeyDescriptor use="signing">
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>####</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
        <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
            Location="https://sso.cnblogs.com/idp/SSO.saml2" />
        <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
            Location="https://sso.cnblogs.com/idp/SSO.saml2" />
    </md:IDPSSODescriptor>
    <md:ContactPerson contactType="administrative">
        <md:Company></md:Company>
        <md:GivenName></md:GivenName>
        <md:SurName></md:SurName>
        <md:EmailAddress></md:EmailAddress>
    </md:ContactPerson>
</md:EntityDescriptor>

ASP.NET MVC实现

  1. Install-Package AspNetSaml
    https://github.com/jitbit/AspNetSaml

  2. web.config

<appSettings>
  <add key="IdpLoginURL" value="https://sso.cnblogs.com/idp/SSO.saml2" />
  <add key="IdpCertificate" value="####" />
  <add key="SpEntityId" value="sp.cnblogs.com" />
  <add key="SpACSURL" value="https://sp.cnblogs.com/sso/acs" />
</appSettings>
  1. 登录逻辑
[HttpPost]
public ActionResult Login(string userName)
{
  if (NeedSSO())
  {
    var url = new AuthRequest(SpEntityId, SpACSURL).GetRedirectUrl(IdpLoginURL);
    return Redirect(url);
  }
}

  1. 回调逻辑
//this is https://sp.cnblogs.com/sso/acs
[HttpPost]
public ActionResult ACS()
{
    string responseString = Request.Form["SAMLResponse"];
    var samlResponse = new Response(IdpCertificate, responseString);
    if (samlResponse.IsValid())
    {
        var userName = samlResponse.GetNameID();
        //other logic
    }
    //other logic
}

完。