mirror of
https://github.com/PlayEdu/PlayEdu
synced 2025-07-24 02:09:35 +08:00
jwt的解析
This commit is contained in:
parent
53b3a8645f
commit
24a9db11c1
44
src/main/java/xyz/playedu/api/PlayEduThreadLocal.java
Normal file
44
src/main/java/xyz/playedu/api/PlayEduThreadLocal.java
Normal file
@ -0,0 +1,44 @@
|
||||
package xyz.playedu.api;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class PlayEduThreadLocal {
|
||||
|
||||
private static final java.lang.ThreadLocal<LinkedHashMap<String, Object>> THREAD_LOCAL = new java.lang.ThreadLocal<>();
|
||||
|
||||
public PlayEduThreadLocal() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入变量
|
||||
*
|
||||
* @param key
|
||||
* @param val
|
||||
*/
|
||||
public static void put(String key, Object val) {
|
||||
LinkedHashMap<String, Object> hashMap = THREAD_LOCAL.get();
|
||||
if (hashMap == null) {
|
||||
hashMap = new LinkedHashMap<>();
|
||||
}
|
||||
hashMap.put(key, val);
|
||||
THREAD_LOCAL.set(hashMap);
|
||||
}
|
||||
|
||||
public static Object get(String key) {
|
||||
return THREAD_LOCAL.get().getOrDefault(key, null);
|
||||
}
|
||||
|
||||
public static Integer getAdminUserID() {
|
||||
return (Integer) get("admin_user_id");
|
||||
}
|
||||
|
||||
public static void setAdminUserId(Integer userId) {
|
||||
put("admin_user_id", userId);
|
||||
}
|
||||
|
||||
public static void remove() {
|
||||
THREAD_LOCAL.remove();
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.domain.AdminUser;
|
||||
import xyz.playedu.api.middleware.AuthMiddleware;
|
||||
import xyz.playedu.api.service.AdminUserService;
|
||||
import xyz.playedu.api.types.PaginationResult;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
@ -15,6 +17,7 @@ public class AdminUserController {
|
||||
@Autowired
|
||||
private AdminUserService adminUserService;
|
||||
|
||||
@AuthMiddleware(prv = SystemConstant.JWT_PRV_ADMIN_USER)
|
||||
@GetMapping("/admin/user/index")
|
||||
public JsonResponse List(@RequestParam(name = "page", defaultValue = "1") Integer page, @RequestParam(name = "size", defaultValue = "10") Integer size) {
|
||||
PaginationResult<AdminUser> result = adminUserService.paginate(page, size, null);
|
||||
|
@ -15,7 +15,7 @@ import xyz.playedu.api.service.AdminUserService;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.types.JwtToken;
|
||||
import xyz.playedu.api.util.MD5Util;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
import xyz.playedu.api.util.RequestUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -38,7 +38,7 @@ public class LoginController {
|
||||
if (adminUser == null) {
|
||||
return JsonResponse.error("邮箱不存在");
|
||||
}
|
||||
String password = MD5Util.md5(loginRequest.getPassword() + adminUser.getSalt()).toLowerCase();
|
||||
String password = HelperUtil.MD5(loginRequest.getPassword() + adminUser.getSalt()).toLowerCase();
|
||||
if (!adminUser.getPassword().equals(password)) {
|
||||
return JsonResponse.error("密码错误");
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package xyz.playedu.api.exception;
|
||||
|
||||
public class JwtLogoutException extends Exception {
|
||||
public JwtLogoutException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public JwtLogoutException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JwtLogoutException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public JwtLogoutException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
protected JwtLogoutException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
12
src/main/java/xyz/playedu/api/middleware/AuthMiddleware.java
Normal file
12
src/main/java/xyz/playedu/api/middleware/AuthMiddleware.java
Normal file
@ -0,0 +1,12 @@
|
||||
package xyz.playedu.api.middleware;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AuthMiddleware {
|
||||
String prv();
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package xyz.playedu.api.middleware.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xyz.playedu.api.middleware.AuthMiddleware;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AuthMiddlewareImpl {
|
||||
|
||||
@Autowired
|
||||
private JWTService jwtService;
|
||||
|
||||
@Pointcut("@annotation(xyz.playedu.api.middleware.AuthMiddleware)")
|
||||
private void doPointcut() {
|
||||
}
|
||||
|
||||
@Around("doPointcut()")
|
||||
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
||||
AuthMiddleware authMiddleware = methodSignature.getMethod().getAnnotation(AuthMiddleware.class);
|
||||
log.info("prv的值:" + authMiddleware.prv());
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
|
||||
}
|
@ -10,7 +10,7 @@ import xyz.playedu.api.service.ImageCaptchaService;
|
||||
import xyz.playedu.api.types.ImageCaptchaResult;
|
||||
import xyz.playedu.api.util.Base64Util;
|
||||
import xyz.playedu.api.util.RedisUtil;
|
||||
import xyz.playedu.api.util.ToolUtil;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
@ -35,7 +35,7 @@ public class ImageCaptchaServiceImpl implements ImageCaptchaService {
|
||||
BufferedImage image;
|
||||
|
||||
// 图形验证码的key[api是无状态的需要key来锁定验证码的值]
|
||||
String randomKey = ToolUtil.randomString(16);
|
||||
String randomKey = HelperUtil.randomString(16);
|
||||
imageCaptcha.setKey(randomKey);
|
||||
|
||||
// 生成验证码
|
||||
|
@ -1,15 +1,18 @@
|
||||
package xyz.playedu.api.service.impl;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.JwtBuilder;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import xyz.playedu.api.exception.JwtLogoutException;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
import xyz.playedu.api.types.JWTPayload;
|
||||
import xyz.playedu.api.types.JwtToken;
|
||||
import xyz.playedu.api.util.ToolUtil;
|
||||
import xyz.playedu.api.util.RedisUtil;
|
||||
import xyz.playedu.api.util.HelperUtil;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -25,25 +28,26 @@ public class JwtServiceImpl implements JWTService {
|
||||
@Value("${playedu.jwt.expire}")
|
||||
private Long ConfigExpire;
|
||||
|
||||
@Value("${playedu.jwt.cache-black-prefix}")
|
||||
private String ConfigCacheBlackPrefix;
|
||||
|
||||
public JwtToken generate(Integer userId, String iss, String prv) {
|
||||
long curTime = System.currentTimeMillis();
|
||||
|
||||
JWTPayload payload = new JWTPayload();
|
||||
payload.setPrv(prv);
|
||||
payload.setIss(iss);
|
||||
payload.setJti(ToolUtil.uuid());
|
||||
payload.setJti(HelperUtil.uuid());
|
||||
payload.setNbf(curTime);
|
||||
payload.setIat(curTime);
|
||||
payload.setExp(curTime + ConfigExpire);
|
||||
payload.setSub(userId);
|
||||
|
||||
SecretKey key = Keys.hmacShaKeyFor(ConfigKey.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
JwtBuilder builder = Jwts.builder();
|
||||
builder.setId(payload.getJti()).setIssuedAt(new Date(payload.getIat())).claim("prv", payload.getPrv());
|
||||
builder.setExpiration(new Date(payload.getExp())).setIssuer(payload.getIss());
|
||||
builder.setSubject(String.valueOf(payload.getSub())).setNotBefore(new Date(payload.getNbf()));
|
||||
builder.signWith(key);
|
||||
builder.signWith(getSecretKey());
|
||||
|
||||
JwtToken token = new JwtToken();
|
||||
token.setToken(builder.compact());
|
||||
@ -52,8 +56,46 @@ public class JwtServiceImpl implements JWTService {
|
||||
return token;
|
||||
}
|
||||
|
||||
public JWTPayload parse(String token) {
|
||||
return null;
|
||||
public JWTPayload parse(String token, String prv) throws JwtLogoutException {
|
||||
Claims claims = parseToken(token, prv);
|
||||
JWTPayload payload = new JWTPayload();
|
||||
|
||||
payload.setSub(Integer.valueOf(claims.getSubject()));
|
||||
payload.setIss(claims.getIssuer());
|
||||
payload.setPrv((String) claims.get("prv"));
|
||||
payload.setNbf(claims.getNotBefore().getTime());
|
||||
payload.setExp(claims.getExpiration().getTime());
|
||||
payload.setIat(claims.getIssuedAt().getTime());
|
||||
payload.setJti(claims.getId());
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
public boolean isInBlack(String jti) {
|
||||
return RedisUtil.exists(getBlackCacheKey(jti));
|
||||
}
|
||||
|
||||
public void logout(String token, String prv) throws JwtLogoutException {
|
||||
Claims claims = parseToken(token, prv);
|
||||
String cacheKey = getBlackCacheKey(claims.getId());
|
||||
Long expire = (claims.getExpiration().getTime() - System.currentTimeMillis()) / 1000;
|
||||
RedisUtil.set(cacheKey, 1, expire);
|
||||
}
|
||||
|
||||
private Claims parseToken(String token, String prv) throws JwtLogoutException {
|
||||
Claims claims = (Claims) Jwts.parserBuilder().setSigningKey(getSecretKey()).require("prv", prv).build().parse(token).getBody();
|
||||
if (isInBlack(claims.getId())) {
|
||||
throw new JwtLogoutException();
|
||||
}
|
||||
return claims;
|
||||
}
|
||||
|
||||
private SecretKey getSecretKey() {
|
||||
return Keys.hmacShaKeyFor(ConfigKey.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private String getBlackCacheKey(String jti) {
|
||||
return ConfigCacheBlackPrefix + jti;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,6 +45,4 @@ public class JWTPayload {
|
||||
*/
|
||||
private String prv;
|
||||
|
||||
private HashMap<String, Object> claims;
|
||||
|
||||
}
|
||||
|
@ -3,14 +3,20 @@ package xyz.playedu.api.util;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class ToolUtil {
|
||||
public class HelperUtil {
|
||||
|
||||
public static String MD5(String text) {
|
||||
return DigestUtils.md5DigestAsHex(text.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 制作UUID
|
@ -1,12 +0,0 @@
|
||||
package xyz.playedu.api.util;
|
||||
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class MD5Util {
|
||||
|
||||
public static String md5(String text) {
|
||||
return DigestUtils.md5DigestAsHex(text.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
@ -84,85 +84,38 @@ public class RequestUtil {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求域名
|
||||
* 示例: https://127.0.0.1
|
||||
*
|
||||
* @return String
|
||||
* @author fzr
|
||||
*/
|
||||
public static String domain() {
|
||||
HttpServletRequest request = RequestUtil.handler();
|
||||
if (request != null) {
|
||||
String requestUrl = request.getRequestURL().toString();
|
||||
List<String> urls = Arrays.asList(requestUrl.split("/"));
|
||||
|
||||
String agree = "http:";
|
||||
if (request.getServerPort() == 443) {
|
||||
agree = "https:";
|
||||
}
|
||||
|
||||
return agree + "//" + urls.get(2).split(":")[0];
|
||||
return urls.get(2).split(":")[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是GET请求
|
||||
*
|
||||
* @return Boolean
|
||||
* @author fzr
|
||||
*/
|
||||
public static Boolean isGet() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (servletRequestAttributes != null) {
|
||||
HttpServletRequest request = servletRequestAttributes.getRequest();
|
||||
return request.getMethod().equals("GET");
|
||||
}
|
||||
return false;
|
||||
return isMethod("GET");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是POST请求
|
||||
*
|
||||
* @return Boolean
|
||||
* @author fzr
|
||||
*/
|
||||
public static Boolean isPost() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (servletRequestAttributes != null) {
|
||||
HttpServletRequest request = servletRequestAttributes.getRequest();
|
||||
return request.getMethod().equals("POST");
|
||||
}
|
||||
return false;
|
||||
return isMethod("POST");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是PUT请求
|
||||
*
|
||||
* @return Boolean
|
||||
* @author fzr
|
||||
*/
|
||||
public static Boolean isPUT() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (servletRequestAttributes != null) {
|
||||
HttpServletRequest request = servletRequestAttributes.getRequest();
|
||||
return request.getMethod().equals("PUT");
|
||||
}
|
||||
return false;
|
||||
return isMethod("PUT");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是DELETE请求
|
||||
*
|
||||
* @return Boolean
|
||||
* @author fzr
|
||||
*/
|
||||
public static Boolean isDelete() {
|
||||
return isMethod("DELETE");
|
||||
}
|
||||
|
||||
public static boolean isMethod(String method) {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (servletRequestAttributes != null) {
|
||||
HttpServletRequest request = servletRequestAttributes.getRequest();
|
||||
return request.getMethod().equals("DELETE");
|
||||
return request.getMethod().equals(method);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -41,5 +41,6 @@ playedu:
|
||||
jwt:
|
||||
key: "eJTJSLPv13fw9twbuPoeicypLqnSfYWL" #32个字符,加密key用来加密jwt的数据[运行本系统之前请务必修改]
|
||||
expire: 1296000 #token有效期[单位:秒,默认15天]
|
||||
cache-black-prefix: "jwt:blk:" #主动注销的token黑名单缓存前缀
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user