EMOS个人教程-第3章 从零构建后端项目进阶篇
1 章节介绍
2 Shiro和JWT技术
2.1 Shiro简介
- 什么是认证?
- 什么是授权?
- Shiro靠什么做认证与授权的?
2.2 JWT简介
- 单点系统中的认证方式
- 集群环境中的JWT认证方式
3 创建JwtUtil工具类
3.1 导入依赖库
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
emos:
jwt:
secret: 123456
expire: 5
cache-expire: 10
3.2 生成令牌
- 密钥
- 过期时间
- 用户ID
3.3 验证令牌的有效性
- 内容是否有效
- 是否过期
package com.example.emos.wx.config.shiro;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
@Slf4j
public class JwtUtil {
@Value("${emos.jwt.secret}")
private String secret;
@Value("${emos.jwt.expire}")
private int expire;
public String createToken(int userId){
Date date=DateUtil.offset(new Date(), DateField.DAY_OF_YEAR,5);
Algorithm algorithm=Algorithm.HMAC256(secret);
JWTCreator.Builder builder= JWT.create();
String token=builder.withClaim("userId",userId).withExpiresAt(date).sign(algorithm);
return token;
}
public int getUserId(String token){
DecodedJWT jwt=JWT.decode(token);
int userId=jwt.getClaim("userId").asInt();
return userId;
}
public void verifierToken(String token){
Algorithm algorithm=Algorithm.HMAC256(secret);
JWTVerifier verifier=JWT.require(algorithm).build();
verifier.verify(token);
}
}
4 把令牌封装成认证对象
4.1 Shiro框架的认证需要用到认证对象
4.2 把令牌字符串做简单的封装
public class OAuth2Token implements AuthenticationToken{}
5 创建OAuth2Realm类(新)
5.1 创建AuthorizingRealm类的子类
5.2 实现认证与授权的方法
@Component
public class OAuth2Realm extends AuthorizingRealm{}
6 刷新令牌应该如何设计?
6.1 为什么要刷新令牌?
- 令牌一旦生成就保存在客户端
- 即便用户一直在登陆使用系统,也不会重新生成令牌
- 令牌到期,用户必须重新登录
- 令牌应该自动续期
6.2 双令牌机制
- 设置长短日期的令牌
- 短日期令牌失效,就用长日期的令牌
6.3 缓存令牌机制
- 令牌缓存到Redis上面
- 缓存的令牌过期时间是客户端令牌的一倍
- 如果客户端令牌过期,缓存令牌没有过期,则生成新的令牌
- 如果客户端令牌过期,缓存令牌也过期了,则用户必须重新登录
7 创建存储令牌的媒介类
- 该类是用于在过滤器和AOP之间传递Token
- 因为使用了ThreadLocal,所以是线程安全的
@Component
public class ThreadLocalToken {
private ThreadLocal<String> local=new ThreadLocal<>();
public void setToken(String token){
local.set(token);
}
public String getToken(){
return local.get();
}
public void clear(){
local.remove();
}
}
8 创建OAuth2Filter类(一)
8.1 判断哪些请求应该被Shiro处理
- options请求直接放行
- 提交application/json数据
- 请求被分成options和post两次
- 其余所有请求都要被Shiro处理
8.2 判断Token是真过期还是假过期
- 真过期,返回提示信息,让用户重新登录
- 假过期,就生成新的令牌,返回给客户端
8.3 存储新令牌
- ThreadLocalToken
- Redis
9 创建OAuth2Filter类(二)
10 创建ShiroConfig类
10.1 把Filter和Realm添加到Shiro框架
10.2 创建四个对象返回给SpringBoot
- SecurityManager
- 用于封装Realm对象
- ShiroFilterFactoryBean
- 用于封装Filter对象
- 设置Filter拦截路径
- LifecycleBeanPostProcessor
- 管理Shiro对象生命周期
- AuthorizationAttributeSourceAdvisor
- AOP切面类
- Web方法执行前,验证权限
11 利用切面类向客户端返回新令牌
- 拦截所有的Web方法返回值
- 判断是否刷新生成新令牌
- 检查ThreadLocal中是否保存令牌
- 把新令牌绑定到R对象中
12 精简返回给客户端的异常内容
12.1 @ControllerAdvice可以全局捕获SpringMVC异常
12.2 判断异常的类型
- 后端数据验证异常
- 精简异常内容
- 未授权异常
- "你不具有相关权限"
- EmosException
- 精简异常内容
- 普通异常
- "后端执行异常"
13 本章总结
分类:
UNIAPP
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了