init
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user