SpringBoot整合Shiro + JWT实现用户认证
登录和用户认证是一个网站最基本的功能,在这篇博客里,将介绍如何用SpringBoot整合Shiro + JWT实现登录及用户认证
Shiro相较于Spring Security而言是一款轻量级的安全框架,使用它我们可以不在数据库中设计权限相关的表,如果我们只需要处理匿名可访问接口和登录后可访问接口,那么使用Shiro将会很方便。在之前的博客里,我介绍了Spring Security的使用,以及JWT的由来等,有需要的可以传送:
【全网最细致】SpringBoot整合Spring Security + JWT实现用户认证
文章目录
登录及访问接口流程
在此使用最基本的用户名密码登录来举例,首次登录流程如下:
用户访问接口流程如下:
SpringBoot整合Shiro + JWT
Shiro整合redis
Shiro进行认证和授权是默认基于session实现的,这里有2个问题,一是我们这里要使用JWT进行用户认证,用户不能通过session方式登录,二是Shiro将权限数据和会话信息保存在session中不能在集群或负载均衡中使用(因为不同服务器中的session不共享)。因此,考虑使用redis来存储shiro的缓存和会话信息,这里我们使用一个开源的shiro-redis-spring-boot-starter的jar包:shiro-redis
pom.xml添加相应依赖
除了一些基本的依赖,我们还需要添加jwt和shiro-redis依赖
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis-spring-boot-starter</artifactId>
<version>3.2.1</version>
</dependency>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
先写一个JWT工具类:JwtUtils
我们需要写一个JWT工具类JwtUtils,该工具类需要有3个功能:生成JWT、解析JWT、判断JWT是否过期。直接上代码:
@Data
@Component
@ConfigurationProperties(prefix = "xiaolinbao.jwt")
public class JwtUtils {
private long expire;
private String secret;
private String header;
// 生成JWT
public String generateToken(long userId) {
Date nowDate = new Date();
Date expireDate = new Date(nowDate.getTime() + 1000 * expire);
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(userId+"")
.setIssuedAt(nowDate)
.setExpiration(expireDate) // 7天过期
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
// 解析JWT
public Claims getClaimsByToken(String jwt) {
try {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(jwt)
.getBody();
} catch (Exception e) {
return null;
}
}
// 判断JWT是否过期
public boolean isTokenExpired(Claims claims) {
return claims.getExpiration().before(new Date());
}
}
登录接口
登录接口是可匿名访问接口,若用户名密码正确,则生成jwt并写入http response的header中返回:
@PostMapping("/login")
public Result login(@Validated @RequestBody LoginDto loginDto, HttpServletResponse response) {
MUser user = userService.getOne(new QueryWrapper<MUser>().eq("username", loginDto.getUsername(