2017-07-14 67 views
2

使用Owin + Oauth2 + Identity2。Web API2身份2承载令牌许可更改

我有一个网络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调用来获取身份。当使用邮递员时,我得到/令牌url并获得我的不记名令牌,在下一个请求中,我将它传递给头并调用我的控制器方法。

[Authorize(Roles = "Templates_Access")] 
    public string Post([FromBody]string value) 
    { 
     return "woo"; 
    } 

这很好,如果用户有权限,它不会允许访问,如果他们这样做。

但是,如果我去我们的网站,使用相同的wcf和数据库,并更改用户权限,如果我发送邮递员相同的请求它仍然允许访问,即使我也删除了该用户分配的角色的权限。

我如何确保在每次请求时“刷新”或再次检查权限?

+0

您想调出您的WCF服务以获取每个请求吗? – DavidG

+0

以及我需要检查权限,这是在数据库上设置的,WCF是唯一的访问我们的数据库。基本上我需要一种方式来检查权限没有改变,如果他们已然后更新会话或任何其他事情,以便授权工作 – lemunk

回答

3

在GrantResourceOwnerCredentials方法中,登录时登录的用户的每个角色都作为声明在登录时存储在不记名令牌中。如果请求必须被授权,则通过AuthorizationFilter的默认实现在存储在不记名令牌中的列表上搜索角色;所以如果你改变用户的权限,你需要一个新的登录名。

这种行为尊重一个问题的REST架构的无状态contraint,如Fielding在他的dissertation写道,而且这是性能和安全性

之间的良好平衡。如果你需要一个不同的行为有一个以上的可能性。

刷新令牌

你可以使用刷新令牌,实现applicationOAuthProvider类的GrantRefreshToken方法;您可以检索刷新的用户权限并创建一个新的访问令牌;这是一篇很好的学习文章how

请记住:在客户端

  • 没有实时影响

    • 更多的复杂性;你必须等待访问令牌到期
    • 如果访问令牌的寿命短,你必须经常(即使用户不会更改权限)来更新它,否则使用寿命长不能解决问题

    检查权限的每个请求

    可以实现自定义AuthorizationFilter并在数据库中检查用户的权限,但它是一个缓慢的解决方案。

    缓存和登录会话

    您可以生成一个用户会话的在GrantResourceOwnerCredentials方法每次登录键(如GUID),并将其存储在承载令牌的要求。您必须使用两个索引将用户会话密钥和userId存储在缓存系统(如Redis)中。 Redis的官方文档解释how

    当用户的permessions被改变,你可以无效的高速缓存系统,用户的每一个会议,由用户id

    搜索可以实现自定义AuthorizationFilter并为您在高速缓存每个请求如果会话有效,按用户会话密钥进行搜索。

    注意:这将违反无国籍限制,你的架构不会问题的REST


    在这里你可以找到标准实施AuthorizaAttribute filter。 您可以创建自定义筛选器,扩展AuthorizeAttribute并覆盖IsAuthorized方法。

    最有可能有其他方式,但多久更改一次用户的权限?在许多系统中,在安全性是第一要求的系统中,如果在活动会话期间更改用户的权限配置,则需要新的登录才能激活新的用户。 您确定需要修改此标准行为吗?

    如果您是这样,我建议使用缓存系统的解决方案。

  • +0

    谢谢你的信息,所以你说的点身份缓存层,然后授权过滤器应该调用缓存检查 – lemunk

    +0

    什么是刷新令牌?它是否会再次呼叫身份以更新结果? – lemunk

    +0

    你必须自己实现刷新令牌的机制,以便刷新用户的权限。我会编辑我的答案,以便更详细。 –

    相关问题