JWT
4阶段的知识, JSON WEB TOEKN , json是指类型, 是个字符串, web 用于web请求, token就是令牌! 身份证!
什么时候出现的这个?? 登录成功 后! 发送到你的浏览器, 你可以自己定义存在什么地方!然后每次发送后台请求的时候, 在请求头中携带着token传到后端!后端解析token,拿到用户信息!
jwt进行token auth 认证! 取消 账号密码明文的认证方式!
前后端分离! cookie 是无法获取到后端的session信息! 那么我们后端如何获取用户登录后的信息?
JWT有什么好处?
1、支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
2、无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
4、更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.(居于前面两点得出这个更适用于CDN内容分发网络)
5、去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.(这个似乎也在继续说前面第一点和第二点的好处。。。)
6、更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
7、CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。(如果token是用cookie保存,CSRF还是需要考虑,一般建议使用1、在HTTP请求中以参数的形式加入一个服务器端产生的token。或者2.放入http请求头中也就是一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中)
ps:后面会推出一些常见的网络安全的处理
8、性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.
9、不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.(知识面太窄,不是太明白这个的意思)
10、基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).
快速入门
1.token的创建
(1)创建maven工程,引入依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
(2)创建类CreateJwtTest,用于生成token
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
/**
* @author: mayuhang <br/>
* Date: 2021/4/29:1:45 <br/>
* Description:
*/
public class CreateJwtTest {
public static void main(String[] args) {
JwtBuilder builder= Jwts.builder().setId("888")
.setSubject("管理员")
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256,"woniuxy");
System.out.println( builder.compact() );
}
}
(3)测试运行,输出如下:
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLnrqHnkIblkZgiLCJpYXQiOjE2MTk2MzIwMzJ9.5de6yHqZn7SMBduX9Xxu04w4WfREjyRLp5e9iqzSnjE
2.token的解析
我们刚才已经创建了token ,在web应用中这个操作是由服务端进行然后发给客户端,客户端在下次向服务端发送请求时需要携带这个token(这就好像是拿着一张门票一样),那服务端接到这个token 应该解析出token中的信息(例如用户id),根据这些信息查询数据库返回相应的结果。
创建ParseJwtTest
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import java.io.UnsupportedEncodingException;
/**
* @author: mayuhang <br/>
* Date: 2021/4/29:1:48 <br/>
* Description:
*/
public class ParseJwtTest {
public static void main(String[] args) {
String token="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJBRE1JTiIsImlhdCI6MTYxOTYzMjQ3NH0.-TJRtXOjhjoU1oD7Y1VLAp2dSQeaVK7aBzRj0ZtTfPw";
Claims claims =
Jwts.parser().setSigningKey("woniuxy").parseClaimsJws(token).getBody();
System.out.println("id:"+claims.getId());
System.out.println("subject:"+claims.getSubject());
System.out.println("IssuedAt:"+claims.getIssuedAt());
}
}
3.自定义claims
我们刚才的例子只是存储了id和subject两个信息,如果你想存储更多的信息(例如角色)可以定义自定义claims
(1) 创建CreateJwtTest3,并存储指定的内容
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
/**
* @author: mayuhang <br/>
* Date: 2021/4/29:1:45 <br/>
* Description:
*/
public class CreateJwtTest {
public static void main(String[] args) {
//为了方便测试,我们将过期时间设置为1分钟
long now = System.currentTimeMillis();//当前时间
long exp = now + 1000*60;//过期时间为1分钟
JwtBuilder builder= Jwts.builder().setId("888")
.setSubject("ADMIN")
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256,"woniuxy")
.setExpiration(new Date(exp))
.claim("roles","admin") //自定义claims存储数据
.claim("logo","logo.png");;
System.out.println( builder.compact() );
}
}
(2) 解析
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author: mayuhang <br/>
* Date: 2021/4/29:1:48 <br/>
* Description:
*/
public class ParseJwtTest {
public static void main(String[] args) {
String token="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJBRE1JTiIsImlhdCI6MTYxOTYzMjg1NSwiZXhwIjoxNjE5NjMyOTE1LCJyb2xlcyI6ImFkbWluIiwibG9nbyI6ImxvZ28ucG5nIn0.D5SFUTBzCvGKp6MECT4-L3pIvU0Umnm__tm-zPSrf1U";
Claims claims =
Jwts.parser().setSigningKey("woniuxy").parseClaimsJws(token).getBody();
System.out.println("id:"+claims.getId());
System.out.println("subject:"+claims.getSubject());
System.out.println("IssuedAt:"+claims.getIssuedAt());
System.out.println("roles:"+claims.get("roles"));
System.out.println("logo:"+claims.get("logo"));
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
System.out.println("签发时间:"+sdf.format(claims.getIssuedAt()));
System.out.println("过期时间:"+sdf.format(claims.getExpiration()));
System.out.println("当前时间:"+sdf.format(new Date()) );
}
}