如何发布重命名用户角色名称的更改

时间:2017-01-24 12:34:08

标签: asp.net asp.net-mvc authentication cookies

我们正在研究ASP.NET MVC应用程序的更改。 我们使用Owin和OAuth2来管理用户权限,但我们自己管理用户数据库对象。

我们在App Startup上有这些:

app.UseKentorOwinCookieSaver();
app.UseCookieAuthentication(GetCookieAuthenticationOptions(AuthenticationType))
   .UseOpenIdConnectAuthentication(GetOpenIdConnectOptions(AuthenticationType));

我们在用户登录时Role手动为用户分配声明enum

claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, user.Role.ToString()));

如果需要更多详细信息,最后会包含授权码。

所有这一切都运行良好,但我们需要重命名一个角色。 代码重命名是微不足道的,当我重命名角色后登录时一切正常。但是,如果我已经登录,当代码更改时,我的旧角色Claim字符串仍然在我的Auth Cookie中,并且不再被Auth代码识别。

因为我已经登录了,它没有带我到LogIn页面 - 它只是向我显示“禁止”错误页面(好像我输入了一个页面的链接,我不应该访问)

因为我们的Auth通过检查您是否具有“角色' x '或任何大于' x '的角色”来工作,因此我们在上获得禁止每个页面(因为现在用户没有任何角色,因此无法每次验证,因为他们的角色无法识别为传递任何测试。

因此,用户无法注销。

作为开发人员,我可以擦除我的浏览器cookie并从头开始登录(此时它可以正常工作)但普通用户(可能是?)将无法做到这一点。

我的第一个想法就是这样做:http://www.britishdeveloper.co.uk/2010/09/force-client-refresh-browser-cache.html,让所有用户注销并让他们在发布后再次登录。 不幸的是,由于每个页面都会失败,我无处可以代码运行给相关用户:(

我可以使用身份验证代码进行破解,以便它知道旧的角色并授予声明权限,但这似乎是 hideous

另一种选择是修改授权代码,以便在用户没有任何已识别的角色时将其记录下来,但是由于某种原因,我无法将手指放在上面。

有关正确方式发布此类更改的任何建议或意见?

= - = - = - = - = - = - = - = - = - =

验证码:

private const string AuthenticationType = "FrontEnd" + CookieAuthenticationDefaults.AuthenticationType;
private const string IdTokenClaimName = "id_token";

public void Configuration(IAppBuilder app)
{
    app.UseKentorOwinCookieSaver();
    app.UseCookieAuthentication(GetCookieAuthenticationOptions(AuthenticationType))
       .UseOpenIdConnectAuthentication(GetOpenIdConnectOptions(AuthenticationType));
}

private static CookieAuthenticationOptions GetCookieAuthenticationOptions(string authenticationType)
{
    return new CookieAuthenticationOptions
       {
           AuthenticationType = authenticationType,
       };
}

private OpenIdConnectAuthenticationOptions GetOpenIdConnectOptions(string authenticationType)
{
    return new OpenIdConnectAuthenticationOptions
           {
               Authority = AuthenticationConstants.AuthenticationAuthority,
               ClientId = AuthenticationConstants.ClientId,
               RedirectUri = AuthenticationConstants.ClientRedirectUrl,
               ResponseType = "id_token",
               Scope = "openid profile email",
               SignInAsAuthenticationType = authenticationType,
               UseTokenLifetime = false,
               Notifications = new OpenIdConnectAuthenticationNotifications
                               {
                                   SecurityTokenValidated = n => Task.Run(() => AuthorizeIfUserExists(n)),
                                   RedirectToIdentityProvider = n => Task.Run(() => SendIdTokenToLogout(n))
                               }
           };
 }

private static void SendIdTokenToLogout(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> n)
{
    if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
    {
        var idTokenHint = n.OwinContext.Authentication.User.FindFirst(IdTokenClaimName).Value;
        n.ProtocolMessage.IdTokenHint = idTokenHint;
    }
}

private void AuthorizeIfUserExists(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> authContext)
{
    var identity = authContext.AuthenticationTicket.Identity;
    var userIdClaim = GetUserIdClaim(identity);
    var emailClaim = GetEmailClaim(identity);

    var claimsIdentity = new ClaimsIdentity(
        identity.AuthenticationType,
        ClaimTypes.Name,
        ClaimTypes.Role);

    claimsIdentity.AddClaim(new Claim(IdTokenClaimName, authContext.ProtocolMessage.IdToken));
    claimsIdentity.AddClaim(userIdClaim);
    claimsIdentity.AddClaim(emailClaim);

    using (var context = new DbDataContext())
    {
        var user = GetAndInitializeUserIfNecessary(context, userIdClaim.Value, emailClaim.Value);

        // We add role and name claims to all successful logins that are also registered in our database.
        if (user != null && !user.IsSoftDeleted)
        {
            claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, user.Role.ToString()));
            claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, String.Format("{0} {1}", user.FirstName, user.Surname)));
        }
    }

    authContext.AuthenticationTicket = new AuthenticationTicket(
        claimsIdentity,
        authContext.AuthenticationTicket.Properties);
}

1 个答案:

答案 0 :(得分:3)

  

我可以使用身份验证代码进行破解,以便它知道旧的角色和授予声明权限,但这看起来很可怕。

这对我来说似乎最好。

您进行了更改,从而打破了具有活动会话的用户的向后兼容性。在这种一般情况下,通常的零停机时间方法是发布支持旧客户端和新客户端的代码,直到您确定没有旧客户端为止,然后删除旧代码。