=============
后端_令牌过滤
=============
1 添加依赖
/pom.xml:
...
org.crazycake
shiro-redis-spring-boot-starter
3.3.1
javax.xml.bind
jaxb-api
2.3.1
cn.hutool
hutool-all
5.3.3
io.jsonwebtoken
jjwt
0.9.1
...
2 添加属性
/src/main/resources/META-INF/spring-devtools.properties:
restart.include.shiro-redis=/shiro-[\\w-\\.]+jar
3 添加配置
/src/main/resources/application.yml:
...
shiro-redis:
enabled: true
redis-manager:
host: 127.0.0.1:6379
weihome:
jwt:
# 加密秘钥
secret: f4e2e52034348f86b67cde581c0f9eb5
# 有效秒数(7天)
expire: 604800
header: Authorization
...
4 添加JWT工具类
/src/main/java/com/weihome/barblog/shiro/JwtUtils.java:
/**
* JWT工具类
*/
@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "weihome.jwt")
public class JwtUtils {
private String secret;
private long expire;
private String header;
/**
* 生成令牌
*/
public String generateToken(long userId) {
Date nowDate = new Date();
//过期时间
Date expireDate = new Date(nowDate.getTime() + expire * 1000);
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(userId+"")
.setIssuedAt(nowDate)
.setExpiration(expireDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Claims getClaimByToken(String token) {
try {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}catch (Exception e){
log.debug("validate is token error ", e);
return null;
}
}
/**
* 令牌是否过期
* @return true:过期
*/
public boolean isTokenExpired(Date expiration) {
return expiration.before(new Date());
}
}
5 添加JWT令牌类
/src/main/java/com/weihome/barblog/shiro/JwtToken.java:
/**
* JWT令牌类
*/
public class JwtToken implements AuthenticationToken {
private String token; // 令牌字符串
public JwtToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
6 添加JWT过滤器类
/src/main/java/com/weihome/barblog/shiro/JwtFilter.java:
/**
* JWT过滤器类
*/
@Component
public class JwtFilter extends AuthenticatingFilter {
@Autowired
JwtUtils jwtUtils;
/**
* 接受或拒绝请求
* 无令牌:接受请求
* 令牌无效:抛出异常
* 令牌有效:根据身份认证结果决定接受或拒绝请求
*/
@Override
protected boolean onAccessDenied(
ServletRequest servletRequest, ServletResponse servletResponse)
throws Exception {
HttpServletRequest request =
(HttpServletRequest) servletRequest;
// 从请求头中获取令牌字符串
String token = request.getHeader("Authorization");
if (StringUtils.isEmpty(token)) // 无令牌
return true; // 接受请求
Claims claim = jwtUtils.getClaimByToken(token);
if (claim == null || jwtUtils.isTokenExpired(
claim.getExpiration())) // 令牌无效
throw new ExpiredCredentialsException("令牌无效,重新登录");
return executeLogin(servletRequest, servletResponse); // 身份认证
}
/**
* 身份认证过程中调用此方法
*/
@Override
protected AuthenticationToken createToken(
ServletRequest servletRequest, ServletResponse servletResponse)
throws Exception {
HttpServletRequest request =
(HttpServletRequest) servletRequest;
// 从请求头中获取令牌字符串
String token = request.getHeader("Authorization");
if (StringUtils.isEmpty(token)) // 无令牌
return null; // 无需身份认证
return new JwtToken(token); // 返回JWT令牌用于身份认证
}
/**
* 身份认证失败时调用此方法
*/
@Override
protected boolean onLoginFailure(
AuthenticationToken authcToken,
AuthenticationException authcException,
ServletRequest servletRequest,
ServletResponse servletResponse) {
HttpServletResponse response =
(HttpServletResponse) servletResponse;
Throwable throwable = authcException.getCause() == null ?
authcException : authcException.getCause();
Result result = Result.error(throwable.getMessage());
String json = JSONUtil.toJsonStr(result);
try {
// 将包含异常信息的Json字符串写入响应
response.getWriter().print(json);
}
catch (IOException ioException) {
}
return false;
}
}