我们正在研究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);
}
答案 0 :(得分:3)
我可以使用身份验证代码进行破解,以便它知道旧的角色和授予声明权限,但这看起来很可怕。
这对我来说似乎最好。
您进行了更改,从而打破了具有活动会话的用户的向后兼容性。在这种一般情况下,通常的零停机时间方法是发布支持旧客户端和新客户端的代码,直到您确定没有旧客户端为止,然后删除旧代码。