簡體   English   中英

Web API2 Identity2承載令牌權限更改

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM