[英]Web API2 identity2 bearer token permission change
使用Owin + Oauth2 + Identity2。
我有一個帶有我已修改的默認基本身份驗證設置的Web Api。
我的startup.cs局部類
public void ConfigureAuth(IAppBuilder app)
{
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);//TODO: prob wont need this
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),//TODO: prob wont need this
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true //TODO: set debug mode
};
// Token Generation
app.UseOAuthBearerTokens(OAuthOptions);
}
我的startup.cs類部分位於根目錄
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureAuth(app);
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
我的applicationOAuthProvider.cs
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//get user
var service = new CarrierApi.CarrierManagementClient();
var result = service.LoginAsync(context.UserName, context.Password);
var user = result.Result.Identity;
//TODO: log stuff here? i.e lastlogged etc?
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = user;
ClaimsIdentity cookiesIdentity = user;
AuthenticationProperties properties = CreateProperties(user.GetUserName());
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
如您所見,我實際上通過wcf調用獲取了我們現有數據庫的身份。 使用郵遞員時,我獲取/ token網址並獲取我的不記名令牌,在下一個請求時,我將其傳遞到標頭中並調用我的控制器方法。
[Authorize(Roles = "Templates_Access")]
public string Post([FromBody]string value)
{
return "woo";
}
如果用戶有權限,則它會允許訪問,如果他們這樣做,則效果很好。
但是,如果我訪問使用相同wcf和DB的網站並更改用戶權限,即使我在郵遞員上發送相同的請求,即使我也刪除了對用戶分配的角色的權限,它仍然允許訪問。
如何確保在每個請求中“刷新”或再次檢查權限?
登錄的用戶的每個角色都在登錄時作為聲明使用GrantResourceOwnerCredentials方法存儲在承載令牌中。 如果必須授權請求,則默認實現AuthorizationFilter在存儲在承載令牌中的列表上搜索角色; 因此,如果您更改用戶的權限,則需要重新登錄。
正如Fielding在其論文中所寫的,這種行為尊重了Restfull架構的無狀態約束,而且這在性能和安全性之間取得了很好的平衡。
如果您需要其他行為,則有不止一種可能性。
刷新令牌
您可以使用Refresh Token,實現applicationOAuthProvider類的GrantRefreshToken方法; 您可以檢索刷新的用戶的權限並創建新的訪問令牌; 這是一個學習的好文章如何 。
記住:
檢查每個請求的權限
您可以實現自定義AuthorizationFilter並在數據庫中檢查用戶的權限,但這是一個緩慢的解決方案。
緩存和登錄會話
您可以在GrantResourceOwnerCredentials方法中為每次登錄生成用戶會話的密鑰(如guid),並將其存儲在承載令牌中作為聲明。 您還必須使用兩個索引將其存儲在緩存系統(如Redis)中:用戶會話的密鑰和userId。 Redis的官方文檔解釋了如何 。
當用戶的權限發生變化時,您可以使該用戶在緩存系統中的每個會話無效,並按userId搜索
您可以實現一個自定義的AuthorizationFilter,並根據用戶會話的密鑰搜索會話是否有效,以檢查緩存中的每個請求。
注意:這將違反無狀態約束,並且您的體系結構將無法充滿
在這里,您可以找到AuthorizaAttribute filter的標准實現。 您可以創建擴展AuthorizeAttribute並覆蓋IsAuthorized方法的自定義過濾器。
很可能還有其他方法,但是多久更改一次用戶權限? 在許多系統中,以及在首先要求安全性的系統中,如果在活動會話期間更改了用戶的權限配置,則必須使用新的登錄名來激活新的登錄名。 您確定需要修改此標准行為嗎?
如果是這樣,我建議使用緩存系統解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.