JWT 认证流程
- 客户端使用用户名和密码请求登陆。
- 服务端收到请求,去验证用户名和密码
- 验证成功后,服务端会签发一个Token,再把这个Token发送给客户端。
- 客户端收到Token以后可以把它存储在Cookie本地。
- 客户端每次向服务端请求资源时需要携带Cookie中该Token。
- 服务端收到请求后,验证客户端携带的Token,如果验证成功则返回数据。
优缺点,组成部分
JWT令牌的优点
- JWT基于ison,非常方便解析。
- 可以在令牌中自定义丰富的内容,易扩展。
- 通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高
- 资源服务使用]WT可不依赖认证服务即完成授权。
JWT令牌的缺点: JWT令牌较长,占存储空间比较大。
一个JWT实际上就一个字符串,它由三部分组成,头部、负载与签名
- 头部:描述关于该IWT的最基本信息,例如其类型以及签名所用的算法(如HMAC SHA256 或 RSA)
- 负载:是存放信息的地方,例如用户的信息。
- 签证:签证信息,由三部分组成: Header (Base64编码后) Payload (Base64编码后) Secret (盐,必须保密),由点组成的加密字符串
代码实践
依赖
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
- 加密,解密,设置过期时间,设置自定义键值对
@Test
void contextLoads() {
// 加密
JwtBuilder jwtBuilder = Jwts.builder().setId("1001") // 设置负载内容
.setSubject("小明") // 这是主体
.setIssuedAt(new Date()) //设置签发时间
.signWith(SignatureAlgorithm.HS256, "QFJAVA");// 前算法,后是盐
String token = jwtBuilder.compact();
System.out.println(token);
// 解密
// Claims:封装的信息
Claims body = Jwts.parser().setSigningKey("QFJAVA").parseClaimsJws(token).getBody();
// 获取自定义的键值对
Object role = body.get("role");
System.out.println(role);
System.out.println(body);
// 设置过期时间
long exp = System.currentTimeMillis() + 1000 * 60;
JwtBuilder builder = Jwts.builder().setId("1001")
.setSubject("小米")
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, "QFJAVA")
// 设置过期时间
.setExpiration(new Date(exp))
.claim("role", "admin"); // 就是键值对,可以设置自己想要的数据,可以拿到Claims对象,get方法获取自己的数据
System.out.println(builder.compact());
}
准备内容
再来说下前端,先配置跨域
module.exports = {
devServer: {
host: '0.0.0.0', // 可以忽略不写
port: 8080, // 它是用来修改你打开后的端口号的
open: true, // 值为 true的话,项目启动时自动打开到浏览器里边, false不会打开
proxy: {
'/api': {
target: 'http://localhost:82', // 跨域请求的公共地址
ws: false, // 也可以忽略不写,不写不会影响跨域
changeOrigin: true, // 是否开启跨域,值为 true 就是开启, false 不开启
pathRewrite: {
'^/api': ''// 注册全局路径, 但是在你请求的时候前面需要加上 /api
}
},
'/bvcsp': {
target: 'https://*****',
changeOrigin: true,
// 忽略https证书错误
secure: false,
rewrite: (p) => p,
// 添加请求头,可以在浏览器看到
bypass: function (req, res, options) {
const proxyUrl = new URL(req.url, options.target).href
res.setHeader( 'x-req-proxyUrl', proxyUrl )
}
},
}
}
}
配置axios,因为配置了跨域,这个时候可以直接写api了
import axios from 'axios'
const request = axios.create({
baseURL: '/api' // 因为配置跨域了
})
// 下面这是拦截器,拦截请求,自动加token令牌
request.interceptors.request.use(
config => {
config.headers.token = `${localStorage.getItem('token')}`
return config
}
)
export default request
说下如何请求前端登录接口POST请求
登录接口就是login,传入username和password就可以了
export const Login = function (data) {
return request({
method: 'post',
url: 'login',
data: qs.stringify(data)
})
}