This commit is contained in:
2026-06-17 21:57:11 +08:00
parent ae96f2c9ff
commit f98c6823b3
336 changed files with 500 additions and 841 deletions
@@ -0,0 +1,131 @@
package com.bc.exam.ability.shiro;
import com.bc.exam.ability.shiro.jwt.JwtToken;
import com.bc.exam.ability.shiro.jwt.JwtUtils;
import com.bc.exam.modules.user.dto.response.SysUserLoginDTO;
import com.bc.exam.modules.user.service.SysUserRoleService;
import com.bc.exam.modules.user.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.List;
/**
* 用户登录鉴权和获取用户授权
* @author chenhaodong
*/
@Component
@Slf4j
public class ShiroRealm extends AuthorizingRealm {
@Autowired
@Lazy
private SysUserService sysUserService;
@Autowired
@Lazy
private SysUserRoleService sysUserRoleService;
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
/**
* 详细授权认证
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userId = null;
if (principals != null) {
SysUserLoginDTO user = (SysUserLoginDTO) principals.getPrimaryPrincipal();
userId = user.getId();
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 查找用户角色
List<String> roles = sysUserRoleService.listRoles(userId);
info.setRoles(new HashSet<>(roles));
log.info("++++++++++校验详细权限完成");
return info;
}
/**
* 校验用户的账号密码是否正确
* @param auth
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
String token = (String) auth.getCredentials();
if (token == null) {
throw new AuthenticationException("token为空!");
}
// 校验token有效性
SysUserLoginDTO user = this.checkToken(token);
return new SimpleAuthenticationInfo(user, token, getName());
}
/**
* 校验Token的有效性
* @param token
* @return
* @throws AuthenticationException
*/
public SysUserLoginDTO checkToken(String token) throws AuthenticationException {
// 查询用户信息
log.debug("++++++++++校验用户token "+ token);
// 从token中获取用户名
String username = JwtUtils.getUsername(token);
log.debug("++++++++++用户名: "+ username);
if (username == null) {
throw new AuthenticationException("无效的token");
}
// 查找登录用户对象
SysUserLoginDTO user = sysUserService.token(token);
// 校验token是否失效
if (!JwtUtils.verify(token, username)) {
throw new AuthenticationException("登陆失效,请重试登陆!");
}
return user;
}
/**
* 清除当前用户的权限认证缓存
* @param principals
*/
@Override
public void clearCache(PrincipalCollection principals) {
super.clearCache(principals);
}
}
@@ -0,0 +1,53 @@
package com.bc.exam.ability.shiro.aop;
import com.bc.exam.ability.shiro.jwt.JwtToken;
import com.bc.exam.aspect.utils.InjectUtils;
import com.bc.exam.modules.Constant;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 鉴权登录拦截器
* @author chenhaodong
*/
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {
/**
* 执行登录认证
* @param request
* @param response
* @param mappedValue
* @return
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
try {
executeLogin(request, response);
return true;
} catch (Exception e) {
// 写出统一错误信息
InjectUtils.restError((HttpServletResponse) response);
return false;
}
}
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader(Constant.TOKEN);
JwtToken jwtToken = new JwtToken(token);
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
getSubject(request, response).login(jwtToken);
// 如果没有抛出异常则代表登入成功,返回true
return true;
}
}
@@ -0,0 +1,33 @@
package com.bc.exam.ability.shiro.jwt;
import lombok.Data;
import org.apache.shiro.authc.AuthenticationToken;
/**
* @author chenhaodong
*/
@Data
public class JwtToken implements AuthenticationToken {
private static final long serialVersionUID = 1L;
/**
* JWT的字符token
*/
private String token;
public JwtToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
@@ -0,0 +1,99 @@
package com.bc.exam.ability.shiro.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.bc.exam.core.utils.file.MD5Util;
import java.util.Calendar;
import java.util.Date;
/**
* JWT工具类
* @author chenhaodong
*/
public class JwtUtils {
/**
* 有效期24小时
*/
private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000;
/**
* 校验是否正确
* @param token
* @param username
* @return
*/
public static boolean verify(String token, String username) {
try {
// 根据密码生成JWT效验器
Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username));
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("username", username)
.build();
// 效验TOKEN
verifier.verify(token);
return true;
} catch (Exception exception) {
return false;
}
}
/**
* 从Token中解密获得用户名
* @param token
* @return
*/
public static String getUsername(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username").asString();
} catch (JWTDecodeException e) {
return null;
}
}
/**
* 生成JWT Token字符串
* @param username
* @return
*/
public static String sign(String username) {
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username));
// 附带username信息
return JWT.create()
.withClaim("username", username)
.withExpiresAt(date).sign(algorithm);
}
/**
* 根据用户名和秘钥,生成一个新的秘钥,用于JWT加强一些安全性
* @param userName
* @return
*/
private static String encryptSecret(String userName){
// 一个简单的登录规则,用户名+当前月份为加密串,意思每个月会变,要重新登录
// 可自行修改此规则
Calendar cl = Calendar.getInstance();
cl.setTimeInMillis(System.currentTimeMillis());
StringBuffer sb = new StringBuffer(userName)
.append("&")
.append(cl.get(Calendar.MONTH));
// 获取MD5
String secret = MD5Util.MD5(sb.toString());
return MD5Util.MD5(userName + "&" + secret);
}
}