起源:

近期帮别人做项目,涉及到OAuth认证,服务端主动使token失效,要使对应用户不能再继续访问,只能重新登陆,或者重新授权。

场景:

这种场景OAuth2.0是支持的,比如用户修改了密码,那所有之前保留在各个客户端的token均失效,要求用户重新提供凭证。

原因:

在之前的项目中,一旦授权服务AuthorizationServer发放了token,所有的资源服务只会通过统一的加密解密算法,解析出token中的信息包括用户身份等,就直接使用了。这样因为不和数据库或外部存储介质交互,所以效率会比较高。以下是在所有资源服务、包括认证服务Web.config中的配置,machineKey必须相同。

  <system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<machineKey decryptionKey="B7E121C5839A624E" validation="SHA1" validationKey="C2B8DF31AB96asd428066DFDA1A479542825F3B48865C4E47AF6A026F2" />
</system.web>

这样效率是提高了,但是每次验证不与后端(尤指存储)交互,所以token一旦发出,除非客户端主动清除或着超出有效时间,否则都有效,有一定的失窃风险。

分析:

.Net在IdentityServer3.0在用户表中使用SecurityStamp字段,作为安全标识,去识别是否失效。默认情况是没有开启验证的,否则就像之前说的每次都会和数据库交互,降低性能。关于SecurityStamp的说明,大家可以看一下这篇文章:

What is ASP.NET Identity's IUserSecurityStampStore<TUser> interface?

This is meant to represent the current snapshot of your user's credentials. So if nothing changes, the stamp will stay the same. But if the user's password is changed, or a login is removed (unlink your google/fb account), the stamp will change. This is needed for things like automatically signing users/rejecting old cookies when this occurs, which is a feature that's coming in 2.0.

    Edit: Updated for 2.0.0. So the primary purpose of the SecurityStamp is to enable sign out everywhere. The basic idea is that whenever something security related is changed on the user, like a password, it is a good idea to automatically invalidate any existing sign in cookies, so if your password/account was previously compromised, the attacker no longer has access.

In 2.0.0 we added the following configuration to hook the OnValidateIdentity method in the CookieMiddleware to look at the SecurityStamp and reject cookies when it has changed. It also automatically refreshes the user's claims from the database every refreshInterval if the stamp is unchanged (which takes care of things like changing roles etc)

文章中给出的代码如下:

app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider {
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});

虽然这篇文章大致讲明白了,这是个什么东西和怎么用,但是仔细想想,还是有问题,因为我们是使用Bearer方式,这里只是Cookie,所以还差点什么。在资源服务中的配置如下:

namespace ResourceServer
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseOAuthBearerAuthentication(new Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationOptions());
}
}
}

所以我们应该更改的是OAuthBearerAuthenticationOptions这个对象。有找到文章参考如下:

Using bearer tokens (ASP.NET Identity 2.0) with WCF Data Services

总结:

在资源服务中,引入Microsoft.AspNet.Identity.Owin包,在Startup中,更改如下代码:

    public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new OAuthBearerAuthenticationProvider()
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<UserManager, User>(
validateInterval: TimeSpan.FromMinutes(),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
}
}

查看SecurityStampValidator类的源码:

public static Func<CookieValidateIdentityContext, Task> OnValidateIdentity<TManager, TUser, TKey>(
TimeSpan validateInterval, Func<TManager, TUser, Task<ClaimsIdentity>> regenerateIdentityCallback,
Func<ClaimsIdentity, TKey> getUserIdCallback)
where TManager : UserManager<TUser, TKey>
where TUser : class, IUser<TKey>
where TKey : IEquatable<TKey>
{
.....
               var user = await manager.FindByIdAsync(userId).WithCurrentCulture();
var reject = true;
// Refresh the identity if the stamp matches, otherwise reject
if (user != null && manager.SupportsUserSecurityStamp)
{
var securityStamp =
context.Identity.FindFirstValue(Constants.DefaultSecurityStampClaimType);
if (securityStamp == await manager.GetSecurityStampAsync(userId).WithCurrentCulture())
{
reject = false;
// Regenerate fresh claims if possible and resign in
if (regenerateIdentityCallback != null)
{
var identity = await regenerateIdentityCallback.Invoke(manager, user).WithCurrentCulture();
if (identity != null)
{
// Fix for regression where this value is not updated
// Setting it to null so that it is refreshed by the cookie middleware
context.Properties.IssuedUtc = null;
context.Properties.ExpiresUtc = null;
context.OwinContext.Authentication.SignIn(context.Properties, identity);
}
}
}
}
          .....
};
}

它会自己判断token中解析出来的securityStamp是否与数据库之前保存的一致,至此,完全解决。

问题:

  • 我们之前说过的,每次请求认证都会请求数据库,降低性能。
  • 资源服务不能独立,必须与用户库绑定。

.Net Identity OAuth 2.0 SecurityStamp 使用的更多相关文章

  1. [转]An introduction to OAuth 2.0 using Facebook in ASP.NET Core

    本文转自:http://andrewlock.net/an-introduction-to-oauth-2-using-facebook-in-asp-net-core/ This is the ne ...

  2. Identity Server 4 预备知识 -- OAuth 2.0 简介

    OAuth 2.0 简介 OAuth有一些定义: OAuth 2.0是一个委托协议, 它可以让那些控制资源的人允许某个应用以代表他们来访问他们控制的资源, 注意是代表这些人, 而不是假冒或模仿这些人. ...

  3. Identity Server 4 原理和实战(完结)_----选看 OAuth 2.0 简介(上)

    https://www.yuque.com/yuejiangliu/dotnet/cg95ni 代表资源所有者的凭据 授权 Authorization Grant 授权是一个代表着资源所有者权限的凭据 ...

  4. ASP.NET WebApi OWIN 实现 OAuth 2.0

    OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. OAuth 允许用户提供一个令牌, ...

  5. NET WebApi OWIN 实现 OAuth 2.0

    NET WebApi OWIN 实现 OAuth 2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和 ...

  6. 基于 IdentityServer3 实现 OAuth 2.0 授权服务数据持久化

    最近花了一点时间,阅读了IdentityServer的源码,大致了解项目整体的抽象思维.面向对象的重要性; 生产环境如果要使用 IdentityServer3 ,主要涉及授权服务,资源服务的部署负载的 ...

  7. 基于 IdentityServer3 实现 OAuth 2.0 授权服务【密码模式(Resource Owner Password Credentials)】

    密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码.客户端使用这些信息,向"服务商提供商"索要授权 ...

  8. 基于 IdentityServer3 实现 OAuth 2.0 授权服务【客户端模式(Client Credentials Grant)】

    github:https://github.com/IdentityServer/IdentityServer3/ documentation:https://identityserver.githu ...

  9. 我也想聊聊 OAuth 2.0 —— Access Token

    这是一篇待在草稿箱半年之久的文章 连我自己都不知道我的草稿箱有多少未发布的文章了.这应该是我在上一家公司未解散之前写的,记得当时是要做一个开发者中心,很不幸. 今天,打开草稿箱有种莫名的伤感,看到这个 ...

随机推荐

  1. CentOS 6.3下搭建Web服务器

    准备前的工作: 1.修改selinux配置文件(/etc/sysconfig/selinux) 关闭防火墙 (1)把SELINUX=enforcing注释掉 (2)并添加SELINUX=disable ...

  2. The import XXX cannot be resolved

    选择project --> clean后,OK.如果还不行,删掉全部import,然后按alt+/提示,逐个导入.

  3. java.lang.NumberFormatException: For input string: "${jdbc.maxActive}"

    一.问题 使用SpringMVC和MyBatis整合,将jdbc配置隔离出来的时候出现下面的错误,百度了很久没有找到解决方法,回家谷歌下,就找到解决方法了,不得不说谷歌就是强大,不废话,下面是具体的错 ...

  4. OBS显示器获取显示黑色没有图像

  5. [Python] 正确复制列表的方法

    new = old[:] Python老鸟都知道以上代码是什么意思.它复制列表old到new.它对于新手来说是种困惑而且应该避免使用这种方法.不幸的是[:]标记法被广泛使用,可能是Python程序员不 ...

  6. Python闭包装饰器笔记

    Python三大器有迭代器,生成器,装饰器,这三个中使用最多,最重要的就是装饰器.本篇将重要从函数嵌套开始讲起,从而引入闭包,装饰器的各种用法等. python中的一切都是一个对象(函数也是) 1.首 ...

  7. JSON调试找不到 net.sf.ezmorph.Morpher

    JSON中,java.lang.NoClassDefFoundError: net/sf/ezmorph/Morpher问题解决 使用JSON,在SERVLET或者STRUTS的ACTION中取得数据 ...

  8. iOS - keychain 详解及变化

    keychain介绍 iOS keychain 是一个相对独立的空间,保存到keychain钥匙串中的信息不会因为卸载/重装app而丢失, .相对于NSUserDefaults.plist文件保存等一 ...

  9. 使用C#把发表的时间改为几个月,几天前,几小时前,几分钟前,或几秒前

    //使用C#把发表的时间改为几个月,几天前,几小时前,几分钟前,或几秒前 //2008年03月15日 星期六 02:35 public string DateStringFromNow(DateTim ...

  10. javaWeb项目重命名的问题

    tomcat项目名称修改 步骤: 1.对工程重命名(选择工程,右键Refactor->Rename)      2.修改Web路径(选择工程,右键Properties->MyEclipse ...