当前位置: 首页 > 知识库问答 >
问题:

ADFS使用Asp进行单点登录。净会员资格

洪宏硕
2023-03-14

这是一个挑战——我要维护一个混合asp。net mvc/web表单应用程序,它使用表单身份验证和旧的asp。net成员资格提供程序(aspnet\u用户、aspnet\u成员资格等)。我们公司正在转向使用ADFS的单点登录。我们必须改变混合asp。net应用程序使用ADFS进行身份验证。

我的问题是,我可以改变混合asp。net应用程序使用ADFS进行身份验证,但继续使用现有的成员资格提供程序来处理授权?

这个计划行得通吗?我的假设正确吗?

>

在asp.net网站中,从ADFS令牌中读取经过身份验证的用户的用户名并调用FormsAuthentication. SetAuthCookie以使成员资格提供程序可用。这将在基本页面类(对于Web表单)或自定义授权属性(对于mvc控制器,覆盖AuthorizeCore)中完成。对于特定用户,调用只会进行一次,我将使用会话变量来跟踪是否进行了调用。

在某种程度上,它可以归结为这个问题:因为我们将使用ADF来验证web。asp的配置。net网站将具有“无”身份验证模式,并拒绝所有匿名用户。使用此web。配置设置时,将调用FormsAuthentication。SetAuthCookie单独启用成员资格提供程序?或者成员资格提供者是否要求将身份验证模式设置为“表单”?

如果您想知道“为什么不试试呢?”,这是因为ADFS服务器将在几个月内不可用,但我现在负责制定一个开发计划。我知道,如果我只需要一个普通的asp。net mvc应用程序,将身份验证模式设置为“无”,并调用成员资格。使用正确的用户名和密码验证用户,然后进行FormsAuthentication。SetAuthCookie成员资格提供程序似乎工作正常,但请求。IsAuthenticated当然是false,所以我没有方便的方法对此进行全面测试,因为每次授权检查都首先查看用户是否经过身份验证,然后再查看角色。

共有2个答案

裴星洲
2023-03-14

这种方法适用于WIF,但如果您使用的是ADFS 4.0,您也可以使用OWIN Katana和OpenID Connect。

OWIN管道允许多个连接,例如此连接。

或者您可以使用像identityserver这样的支持ASP的东西。NET成员身份,您可以将其与ADF联合。identityserver将有两个按钮,用户可以选择使用哪个按钮进行身份验证。

段干河
2023-03-14

事实证明这非常简单。我使用的是Framework 4.7和Windows Server 2016。注意——其他版本的Framework和Windows Server有完全不同的说明。

按照下面的步骤操作后,我成功地将ADFS集成到一个使用成员资格的asp.netWeb应用程序中。对成员资格数据库的所有现有调用都可以工作(例如,成员资格。Getuser()、角色。GetRtisForUser())。此外,System. Thread。线程。货币校长。身份功能齐全。IsInRole()和[Authorize]属性等调用无需更改即可工作。

这不是一个详细的演练,只是对我必须在web应用程序中更改的内容的粗略描述(设置ADF是一个完全独立的问题)。

设置ADFS后,在指向ADFS的Web应用程序中创建一个联邦etadata.xml文件。谷歌搜索有关创建联邦etadata.xml文件的说明。注意:不要使用框架3.5 Windows身份联合实用程序来创建您的联邦ata.xml;该实用程序将更改您的web.config以使用已弃用的Micorsoft。身份库。您将改为使用系统。身份库。我的联邦etadata.xml文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<EntityDescriptor ID="_ff25f54f-e839-4005-9dc5-bb598b34a50d" entityID="https://MyServer.MyCompany.com/ADFSAuthentication/" xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
  <RoleDescriptor xsi:type="fed:ApplicationServiceType" xmlns:fed="http://docs.oasis-open.org/wsfed/federation/200706" protocolSupportEnumeration="http://docs.oasis-open.org/wsfed/federation/200706" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <fed:TargetScopes>
      <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Address>https://MyServer.MyCompany.com/ADFSAuthentication/</wsa:Address>
      </wsa:EndpointReference>
      <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Address>https://MyServer.MyCompany.com/ADFSAuthentication/</wsa:Address>
      </wsa:EndpointReference>
    </fed:TargetScopes>
    <fed:PassiveRequestorEndpoint>
      <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Address>https://MyServer.MyCompany.com/ADFSAuthentication/</wsa:Address>
      </wsa:EndpointReference>
    </fed:PassiveRequestorEndpoint>
  </RoleDescriptor>
</EntityDescriptor>

在您的web中。配置:1。使您的FederationMetadata文件可见

<location path="FederationMetadata">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
  </location>

关闭身份验证,并拒绝所有未经授权的用户。

<system.web>
<authorization>
  <deny users="?" />
</authorization>
<authentication mode="None" />

...

保留现有的成员资格和角色提供程序以方便使用。在角色提供程序中,设置cacheRolesInCookie=“false”。角色现在由SessionAuthenticationModule维护。如果在Cookie中缓存角色,则会中断SessionAuthenticationModule。

添加系统所需的应用程序设置。标识,它指向ADF。

  <appSettings>
<add key="ida:FederationMetadataLocation" value="https://adfs.MyCompany.com/federationmetadata/2007-06/FederationMetadata.xml" />
<add key="ida:Issuer" value="http://adfs.MyCompany.com/adfs/ls/" />
<add key="ida:ProviderSelection" value="productionSTS" />
<add key="ida:EnforceIssuerValidation" value="false" />

...

将WSFederationAuthenticationModule和SessionAuthenticationModule添加到系统中。Webserver标记。SO站点中的一些错误是不允许我在此处添加标记,因此我将在下面添加该标记作为注释。WSFederationAuthenticationModule中断401授权被拒绝的HTTP响应,并重定向到ADFS。ADFS发出安全令牌。WSFederationAuthenticationModule使用该令牌,创建一个ClaimsPrincipal,并将该ClaimsPrincipal存储在cookie中(这将浏览器标记为已验证)。在每次回发时,SessionAuthenticationModule都会使用该cookie来重建ClaimsPrincipal(因此,用户不需要在每次回发时使用ADFS进行重新验证)。像“IsAuthenticated”和“IsInRole()”这样的调用以及[授权]标记都可以从此ClaimsPrincipal对象中工作。

设置您的系统。标识模型标签与您的ADFS通信。完整的说明超出了此答案的范围,但我的标签如下所示:

<system.identityModel>
<identityConfiguration>
  <audienceUris>
    <add value="https://MyServer.MyCompany.com/ADFSAuthentication/" />
  </audienceUris>
  <!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
  <certificateValidation certificateValidationMode="None" />
  <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
    <authority name="http://adfs.MyCompany.com/adfs/services/trust">
      <keys>
        <add thumbprint="MyGuid" />
      </keys>
      <validIssuers>
        <add name="http://adfs.MyCompany.com/adfs/services/trust" />
      </validIssuers>
    </authority>
  </issuerNameRegistry>
  <securityTokenHandlers>
    <add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  </securityTokenHandlers>
</identityConfiguration>

保留指向成员数据库的现有连接字符串。这通常默认为“LocalSqlServer”:

  <connectionStrings>
<clear />
<add name="LocalSqlServer" connectionString="Server=MyServer; Database=MyMembershipDatabase; Integrated Security=SSPI;" providerName="System.Data.SqlClient" />

在global.asax.中的Authenticate_Request事件中从成员数据库加载用户的角色在我们的例子中,我们使用Active Directory“对象GUID”作为AD用户的唯一标识符;我们在成员数据库中的dbo.aspnet_users表中添加了一列,以将AD用户与成员用户联系起来。从那里,一个简单的SQL调用将角色从成员数据库加载到货币校长中。身份,将后者转换为ClaimsIdentity。在下面的示例中,我添加了3个硬编码角色,但实际上这些角色将使用对象GUID从我们的成员数据库中检索。

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
        var currentPrincipalIdentity = (System.Security.Claims.ClaimsIdentity)System.Threading.Thread.CurrentPrincipal.Identity;
        var claims = currentPrincipalIdentity.Claims.ToList();

        //if WSFederationAuthenticationModule just fired (aka user's first visit) the claims have not been loaded yet.
        //if SessionAuthenticationModule just fired (aka the user has a valid security token cookie) then no need to reload the claims, they are a part of Thread.CurrentPrincipal
        if (!claims.Exists(o => o.Type == "MyCompany/objectGUID_decoded"))
        {
            //get the encoded guid.  if this does not exist exit immediately, the user has no business in our web site
            var encodedGuidClaim = claims.FirstOrDefault(o => o.Type == "MyCompany/objectGUID");
            if (encodedGuidClaim == null)
                return;

            currentPrincipalIdentity.AddClaim(new System.Security.Claims.Claim("MyCompany/objectGUID_decoded", new Guid(Convert.FromBase64String(encodedGuidClaim.Value)).ToString()));

            //we will need a new column or table in membership database to link users to the ActiveDirectory objectGUID.
            //if the user has multiple identities we will load the default (the default must exist)
            //for this example I am hard-coding the MyCompany/userID guid, but in fact it will be the single or default userID guid for the user
            currentPrincipalIdentity.AddClaim(new System.Security.Claims.Claim("MyCompany/userID", "310860D2-6329-41B7-AF44-E8DC2113B4C7"));

            //for this example I am hard-coding the roles, but in face we will load the user's roles from database using the userId retrieved in the line above.
            //when user changes identity then we need to write a new cookie with the new roles collection, see ExampleOfHowToChangeIdentity() above.
            currentPrincipalIdentity.AddClaim(new System.Security.Claims.Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "MyRole1"));
            currentPrincipalIdentity.AddClaim(new System.Security.Claims.Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "MyRole2"));
            currentPrincipalIdentity.AddClaim(new System.Security.Claims.Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "MyRole3"));
        }
    }

在我们的应用程序中,单个Active Directory用户可以具有多个成员身份。有时用户会想要更改成员身份。这很容易做到:

private void ExampleOfHowToChangeIdentity(Guid newIdentity)
{
//assume that a user has multiple identies and is logged in as the default.
//the user now selects a new identity
var currentPrincipalIdentity = (System.Security.Claims.ClaimsIdentity)System.Threading.Thread.CurrentPrincipal.Identity;
var allClaims = currentPrincipalIdentity.Claims.ToList();

//first remove all of the roles from old identity
var allRoles = allClaims.Where(o => o.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role").ToList();
foreach (var role in allRoles)
{
    currentPrincipalIdentity.RemoveClaim(role);
}

//second, fetch the new claims from the database using the newIdentity
//we will have a column or table in the Membership database that matches this guid to the UserId
//below I am hard-coding some new claims, but in fact they will be added from a database call.
currentPrincipalIdentity.AddClaim(new System.Security.Claims.Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Nonesuch"));
currentPrincipalIdentity.AddClaim(new System.Security.Claims.Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Nonesuch2"));
currentPrincipalIdentity.AddClaim(new System.Security.Claims.Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Nonesuch3"));

//third, replace the MyCompany/userID claim with that of the new identity
//this will always be hard-coded.  this is read by Application_AuthenticateRequest each time the user visits the site
currentPrincipalIdentity.RemoveClaim(allClaims.Single(o => o.Type == "MyCompany/userID"));
currentPrincipalIdentity.AddClaim(new System.Security.Claims.Claim("MyCompany/userID", newIdentity.ToString()));

//four, create a new session security token 
//cast to pass into session security token constructor
var claimsPrincipal = new System.Security.Claims.ClaimsPrincipal(currentPrincipalIdentity);
var token = new System.IdentityModel.Tokens.SessionSecurityToken(claimsPrincipal);
System.IdentityModel.Services.FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(token);
}
 类似资料:
  • 我的一个客户想使用ADFS实现SSO。我正在考虑在Azure中使用ADFS进行同样的POC。但一个要求是只有一些用户具有ADFS登录,其他用户需要使用身份提供者使用自定义身份验证。 是否可以在同一web应用程序中使用自定义和ADFS身份验证?例如,使用SSO登录页面或使用凭据登录页面? 我的客户刚刚共享了federatedmetadata。xml。(创建新项目时,是否需要提供完整的URL DNS名

  • 该应用程序托管在IIS 7上,asp.net应用程序,用户需要由身份提供者进行身份验证,身份提供者是Active Directory。为此,我需要生成依赖方信任以添加到ADFS身份提供者。该应用程序托管在未连接到域的Web服务器上,因此我无法在Web服务器上安装ADFS以生成依赖方信任并实现自动或单点登录并生成依赖方信任元数据。我如何为用户实现单点或自动登录-我如何在没有活动目录联合服务的情况下从

  • 我们目前正在使用SAML2.0和ADFS 2.0为客户门户中的客户在RightNow中实现SSO,但该过程返回错误代码17:“SSO_CONTACT_TOKEN_VALIDATE_FAILED” IdP 使用联系信息(客户的登录名作为断言主体)生成已签名的 SAML 2.0 断言。ADFS 2.0 使用 HTTP POST 绑定提交以下断言: 可能是 SAML 断言中的问题吗?

  • 我是一个新手在jeter工具。我想测试登录到一个asp.net网站。但是我在网上搜索了2天后没有成功。 我在下面列出了我遵循的步骤: > 添加一个。 添加一个。 为EVENTVALIDATION和VIEWSTATE添加两个正则表达式提取器。 添加HTTP URL重写修改器与(检查和)。 有两个页面,一个是,另一个是。在Login Post Page中,我添加了以下参数: 用户名: __EVENTV

  • 我的任务是为我们的客户实施单点登录,作为我们下一个版本的一部分。流程如下: 用户使用学校提供给他/她的学生ID/密码登录学校的主要门户系统。 用户点击我公司产品的链接。 用户会自动进入仪表板页面,就好像他们刚刚通过我们网站上的登录表单登录一样。 因此,有两种机制可以将用户验证到我们的站点: 访问我们产品的主页,并使用我们存储在本地系统中的电子邮件/密码登录。 使用单点登录,学生已经使用学生id和密

  • 我正在尝试通过SAML请求将SSO集成到我们的ASP. NET应用程序中。我正在使用KentorAuthService库来实现这一点。使用kentor库是否是从其他身份提供者(例如(一次登录、快速身份等)进行身份验证的解决方案,或者我应该专门基于身份提供者实施。