【问题标题】:Web API2 identity2 bearer token permission changeWeb API 2 身份 2 不记名令牌权限更改
【发布时间】:2017-07-14 12:34:13
【问题描述】:

使用 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);
    }

我的应用程序OAuthProvider.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 url 并获取我的不记名令牌,在下一个请求中,我将其传递到标头并调用我的控制器方法。

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

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

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

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

【问题讨论】:

  • 您想为每个发出的请求调用 WCF 服务吗?
  • 好吧,我需要检查在数据库上设置的权限,wcf 是我们数据库的唯一访问权限。基本上我需要一种方法来检查权限没有改变,如果他们已经更新了会话或任何授权工作

标签: c# oauth-2.0 asp.net-web-api2 asp.net-identity-2


【解决方案1】:

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

这种行为尊重了 Restfull 架构的无状态约束,正如 Fielding 在他的 dissertation 中所写,这也是性能和安全性之间的良好平衡

如果您需要不同的行为,则有多种可能性。

刷新令牌

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

记住:

  • 客户端更复杂
  • 没有实时效果;您必须等待访问令牌过期
  • 如果 Access Token 的生命周期很短,你必须经常更新它(即使用户权限没有改变),否则生命周期长并不能解决问题

检查每个请求的权限

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

缓存和登录会话

您可以在 GrantResourceOwnerCredentials 方法中为每次登录生成用户会话的密钥(如 guid),并将其作为声明存储在不记名令牌中。您还必须使用两个索引将它存储在缓存系统(如 Redis)中:用户会话的密钥和用户 ID。 Redis 的官方文档解释了how

当用户的权限发生变化时,可以在缓存系统中使该用户的每个会话失效,通过userId搜索

如果会话有效,您可以实现自定义 AuthorizationFilter 并检查缓存中的每个请求,通过用户会话的键进行搜索。

小心:这将违反无状态约束,并且您的架构不会完全恢复


在这里您可以找到AuthorizaAttribute filter 的标准实现。 您可以创建自定义过滤器,扩展 AuthorizeAttribute 并覆盖 IsAuthorized 方法。

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

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

【讨论】:

  • 谢谢你的信息,所以你说点身份到缓存层,然后授权过滤器应该调用缓存来检查
  • 刷新令牌呢?是否会再次调用身份来更新结果?
  • 你必须自己实现刷新令牌的机制,这样你才能刷新用户的权限。我将编辑我的答案以更详细。
猜你喜欢
  • 2016-04-07
  • 2014-10-13
  • 1970-01-01
  • 2015-12-25
  • 2013-11-25
  • 2017-08-16
  • 1970-01-01
  • 2014-07-06
  • 1970-01-01
相关资源
最近更新 更多