基于JWT(Json Web Token)的授权方式

JWT 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;

从客户端请求服务器获取token, 用该token 去访问实现了jwt认证的web服务器。 token 可保存自定义信息,如用户基本信息, web服务器用key去解析token,就获取到请求用户的信息了;

很方便解决跨域授权的问题,因为跨域无法共享cookie,.net平台集成的 FormAuthentication 认证系统是基于Session保存授权信息,拿不到cookie就无法认证,用jwt完美解决了。

很多时候,web服务器和授权服务器是同一个项目,所以也可以用以下架构:

实现JWT授权

1.vs2015 新建一个WebApi,安装下面的库,可用nuget 或 命令安装:

install-package Thinktecture.IdentityModel.Core
install-package Microsoft.Owin.Security.Jwt

2.把Startup.Auth.cs 下的 ConfigureAuth 方法清空掉,改为:


public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
var issuer = ConfigurationManager.AppSettings["issuer"];
var secret = TextEncodings.Base64Url.Decode(Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(ConfigurationManager.AppSettings["secret"]))); //用jwt进行身份认证
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { "Any" },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
}
}); app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
//生产环境设为false
AllowInsecureHttp = true,
//请求token的路径
TokenEndpointPath = new PathString("/oauth2/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(30),
//请求获取token时,验证username, password
Provider = new CustomOAuthProvider(),
//定义token信息格式
AccessTokenFormat = new CustomJwtFormat(issuer, secret),
}); }
}

3.ConfigureAuth中的 AccessTokenFormat = new CustomJwtFormat(issuer, secret)是自定义token 保存的信息格式, CustomJwtFormat.cs 类代码


/// <summary>
/// 自定义 jwt token 的格式
/// </summary>
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly byte[] _secret;
private readonly string _issuer; public CustomJwtFormat(string issuer, byte[] secret)
{
_issuer = issuer;
_secret = secret;
} public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
} var signingKey = new HmacSigningCredentials(_secret);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc; return new JwtSecurityTokenHandler().WriteToken(new JwtSecurityToken(_issuer, "Any", data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey));
} public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}

4.ConfigureAuth中的 Provider = new CustomOAuthProvider() 是自定义验证username, password 的,可以用它来实现访问数据库的验证业务逻辑,CustomOAuthProvider.cs类代码

    /// <summary>
/// 自定义 jwt oauth 的授权验证
/// </summary>
public class CustomOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var username = context.UserName;
var password = context.Password;
string userid;
if (!CheckCredential(username, password, out userid))
{
context.SetError("invalid_grant", "The user name or password is incorrect");
context.Rejected();
return Task.FromResult<object>(null);
}
var ticket = new AuthenticationTicket(SetClaimsIdentity(context, userid, username), new AuthenticationProperties());
context.Validated(ticket); return Task.FromResult<object>(null);
} public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
} private static ClaimsIdentity SetClaimsIdentity(OAuthGrantResourceOwnerCredentialsContext context, string userid, string usercode)
{
var identity = new ClaimsIdentity("JWT");
identity.AddClaim(new Claim("userid", userid));
identity.AddClaim(new Claim("username", usercode));
return identity;
} private static bool CheckCredential(string usernme, string password, out string userid)
{
var success = false;
// 用户名和密码验证
if (usernme == "admin" && password == "admin")
{
userid = "1";
success = true;
}
else
{
userid = "";
}
return success;
}
}

5.Web.config 添加 issue 和 secret

  <appSettings>
<add key="issuer" value="test"/>
<!--32个字符的secret-->
<add key="secret" value="12345678123456781234567812345678"/>
</appSettings>

使用

强烈建议用 chrome 的 postman 插件来调试

  1. 获取token

  2. 用token请求数据

header 要添加 Authorization , 值为: Bearer [token], 获取到的 token 替换 [token], 如

Authorization   Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiIxIiwidXNlcmNvZGUiOiIxIiwiaXNzIjoidGVzdCIsImF1ZCI6IkFueSIsImV4cCI6MTQ4NzI0MTQ5MCwibmJmIjoxNDg0NjQ5NDkwfQ.RaWlJC3OF0RNz4mLtuW4uQtRKDHF8RXwZwzIcbZoNOo

JWT缺点

  1. 一旦拿到token, 可用它访问服务器,直到过期,中间服务器无法控制它,如是它失效(有解决方案: 在 token 中保存信息,可添加额外的验证,如加一个 flag, 把数据库对应的flag失效,来控制token有效性)。
  2. token 的过期时间设置很关键,一般把它设到凌晨少人访问时失效,以免用户使用过程中失效而丢失数据。
  3. token保存的信息有限,且都是字符串。

Demo源码

开箱即用 - jwt 无状态分布式授权的更多相关文章

  1. jwt 无状态分布式授权

    基于JWT(Json Web Token)的授权方式 JWT 是JSON风格轻量级的授权和身份认证规范,可实现无状态.分布式的Web应用授权: 从客户端请求服务器获取token, 用该token 去访 ...

  2. 基于JWT的无状态分布式授权【本文摘自智车芯官网】

    简介 JWT是一种用于HTTP交互双方之间传递安全信息的简洁的.安全的表述性声明规范.JWT作为一个开发的标准,它定义了一种简洁的,自包含的方法用于通信双发之间以JSON形式安全传递.且因为数字证书的 ...

  3. shiro jwt 构建无状态分布式鉴权体系

    一:JWT 1.令牌构造 JWT(json web token)是可在网络上传输的用于声明某种主张的令牌(token),以JSON 对象为载体的轻量级开放标准(RFC 7519). 一个JWT令牌的定 ...

  4. 基于Volley,Gson封装支持JWT无状态安全验证和数据防篡改的GsonRequest网络请求类

    这段时间做新的Android项目的client和和REST API通讯框架架构设计.使用了非常多新技术,终于的方案也相当简洁优雅.client仅仅须要传Java对象,server端返回json字符串, ...

  5. C#实现JWT无状态验证的实战应用

    前言 本文主要介绍JWT的实战运用. 准备工作 首先我们创建一个Asp.Net的,包含MVC和WebApi的Web项目. 然后使用Nuget搜索JWT,安装JWT类库,如下图. 设计思路 这里我们简单 ...

  6. ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统

    为什么使用 Jwt 最近,移动开发的劲头越来越足,学校搞的各种比赛都需要用手机 APP 来撑场面,所以,作为写后端的,很有必要改进一下以往的基于 Session 的身份认证方式了,理由如下: 移动端经 ...

  7. Spring Boot Security 整合 JWT 实现 无状态的分布式API接口

    简介 JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案.JSON Web Token 入门教程 - 阮一峰,这篇文章可以帮你了解JWT的概念.本文重点讲解Spring Boo ...

  8. JWT+Interceptor实现无状态登录和鉴权

    无状态登录原理 先提一下啥是有状态登录 单台tomcat的情况下:编码的流程如下 前端提交表单里用户的输入的账号密码 后台接受,查数据库, 在数据库中找到用户的信息后,把用户的信息存放到session ...

  9. 从有状态应用(Session)到无状态应用(JWT),以及 SSO 和 OAuth2

    不管用哪种方式认证用户,都可能被中间人攻击窃取 SessionID 或 Token,从而发生 CSRF 攻击.解决方式就是全站 HTTPS.现在 Let's Encrypt 已经支持免费的通配符 HT ...

随机推荐

  1. Cordova插件开发

    我在网上找了很多关于Cordova插件开发的例子,都不是我想要的,我只想要,怎么调用这个生成出来的js,最终得到了最为直接又简单的方法,希望给能帮助到大家! document.addEventList ...

  2. mytop

    http://jeremy.zawodny.com/mysql/mytop/mytop.html 内容有点过时,用?查看帮助 vi set nuset nonu总记不住

  3. JQuery UI 封装了一些常用模板

    1.css 他已经封装了一些css样式,如果不喜欢,可以直接修改. 2.js 他已经封装了对应的js.

  4. HDU 2489 Minimal Ratio Tree 最小生成树+DFS

    Minimal Ratio Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  5. DNS服务器搭建(主、从、缓)

    主dns服务器搭建 在本机上搭建一个管理hngd.com域名的域名服务器1. 确保安装好以下bind域名服务器 [root@主人 ~]# rpm -qa |grep ^bindbind-chroot- ...

  6. memcached 第二篇----安装使用

    摘要:set add replace get delete gets cas stats 和 flush_all 命令 获取所有key  .你可以使用MemCachedClient的statsItem ...

  7. Java-JNA调用DLL(转)

    源:JNA调用DLL 介绍 给大家介绍一个最新的访问本机代码的Java框架—JNA. JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的J ...

  8. SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解

    SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解 博客分类: 跟开涛学SpringMVC   6.6.2.@RequestParam绑定单个请求参数值 @RequestParam用于 ...

  9. [转]Go语言(golang)开源项目大全

    内容目录 Astronomy 构建工具 缓存 云计算 命令行选项解析器 命令行工具 压缩 配置文件解析器 控制台用户界面 加密 数据处理 数据结构 数据库和存储 开发工具 分布式/网格计算 文档 编辑 ...

  10. Map笔记

    Map,是一个接口,是以键值对的方式存储的,并且键是无序且不可重复的.Map和Collection没有什么关系,Map是一对一对的存,而Collection是一个一个的存. 下面有一个子接口:Sort ...