mirror of
https://github.com/PlayEdu/PlayEdu
synced 2025-06-23 12:32:41 +08:00
完成登录校验
This commit is contained in:
parent
24a9db11c1
commit
bd5cf234f1
49
pom.xml
49
pom.xml
@ -17,13 +17,15 @@
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-json</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -38,50 +40,63 @@
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.5.3</version>
|
||||
</dependency>
|
||||
|
||||
<!--表单验证 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--图形验证码依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.github.penggle</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
<version>2.3.2</version>
|
||||
</dependency>
|
||||
|
||||
<!--Fastjson2 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.22</version>
|
||||
<version>2.0.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2-extension</artifactId>
|
||||
<version>2.0.21</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -96,6 +111,7 @@
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
@ -113,6 +129,7 @@
|
||||
<version>0.11.5</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
16
src/main/java/xyz/playedu/api/bus/BackendBus.java
Normal file
16
src/main/java/xyz/playedu/api/bus/BackendBus.java
Normal file
@ -0,0 +1,16 @@
|
||||
package xyz.playedu.api.bus;
|
||||
|
||||
import xyz.playedu.api.constant.BackendConstant;
|
||||
|
||||
public class BackendBus {
|
||||
|
||||
public static boolean inUnAuthWhitelist(String uri) {
|
||||
for (int i = 0; i < BackendConstant.UN_AUTH_URI_WHITELIST.length; i++) {
|
||||
if (uri.equals(BackendConstant.UN_AUTH_URI_WHITELIST[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package xyz.playedu.api.config;
|
||||
|
||||
import com.alibaba.fastjson2.support.spring.data.redis.FastJsonRedisSerializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
@Configuration
|
||||
@ -13,14 +13,17 @@ public class RedisConfig {
|
||||
@Bean(name = "redisTemplate")
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
||||
GenericJackson2JsonRedisSerializer JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
|
||||
|
||||
redisTemplate.setConnectionFactory(redisConnectionFactory);
|
||||
redisTemplate.setValueSerializer(JsonRedisSerializer);
|
||||
|
||||
// key值采用StringRedisSerializer序列化
|
||||
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
||||
redisTemplate.setKeySerializer(stringRedisSerializer);
|
||||
redisTemplate.setHashKeySerializer(stringRedisSerializer);
|
||||
redisTemplate.setHashValueSerializer(JsonRedisSerializer);
|
||||
|
||||
// value值采用fastjson2序列化
|
||||
FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
|
||||
redisTemplate.setValueSerializer(fastJsonRedisSerializer);
|
||||
redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
|
||||
|
||||
return redisTemplate;
|
||||
}
|
||||
|
68
src/main/java/xyz/playedu/api/config/WebMvcConfig.java
Normal file
68
src/main/java/xyz/playedu/api/config/WebMvcConfig.java
Normal file
@ -0,0 +1,68 @@
|
||||
package xyz.playedu.api.config;
|
||||
|
||||
import com.alibaba.fastjson2.JSONReader;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.alibaba.fastjson2.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import xyz.playedu.api.middleware.AdminAuthMiddleware;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Resource
|
||||
private AdminAuthMiddleware adminAuthMiddleware;
|
||||
|
||||
@Value("${playedu.cors.origins}")
|
||||
private String ConfigOrigins;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(adminAuthMiddleware).addPathPatterns("/backend/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
WebMvcConfigurer.super.addResourceHandlers(registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**").allowedOrigins(ConfigOrigins).allowedHeaders("*").allowedMethods("GET", "POST", "DELETE", "PUT").maxAge(3600);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
converters.add(fastJsonHttpMessageConverter());
|
||||
}
|
||||
|
||||
private HttpMessageConverter<?> fastJsonHttpMessageConverter() {
|
||||
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
|
||||
|
||||
// 中文乱码解决方案
|
||||
List<MediaType> mediaTypes = new ArrayList<>();
|
||||
mediaTypes.add(MediaType.APPLICATION_JSON);
|
||||
fastConverter.setSupportedMediaTypes(mediaTypes);
|
||||
|
||||
// 配置
|
||||
FastJsonConfig fastJsonConfig = new FastJsonConfig();
|
||||
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
fastJsonConfig.setWriterFeatures(JSONWriter.Feature.PrettyFormat);
|
||||
fastConverter.setFastJsonConfig(fastJsonConfig);
|
||||
|
||||
return fastConverter;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package xyz.playedu.api.constant;
|
||||
|
||||
public class BackendConstant {
|
||||
public final static String[] UN_AUTH_URI_WHITELIST = {"/backend/v1/system/image-captcha", "/backend/v1/auth/login",};
|
||||
}
|
@ -1,24 +1,25 @@
|
||||
package xyz.playedu.api.controller.admin;
|
||||
package xyz.playedu.api.controller.backend;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
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;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequestMapping("/backend/v1/admin-user")
|
||||
public class AdminUserController {
|
||||
|
||||
@Autowired
|
||||
private AdminUserService adminUserService;
|
||||
|
||||
@AuthMiddleware(prv = SystemConstant.JWT_PRV_ADMIN_USER)
|
||||
@GetMapping("/admin/user/index")
|
||||
@GetMapping("/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);
|
||||
return JsonResponse.data(result);
|
@ -1,4 +1,4 @@
|
||||
package xyz.playedu.api.controller.admin;
|
||||
package xyz.playedu.api.controller.backend;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.domain.AdminUser;
|
||||
import xyz.playedu.api.exception.JwtLogoutException;
|
||||
import xyz.playedu.api.middleware.ImageCaptchaCheckMiddleware;
|
||||
import xyz.playedu.api.request.LoginRequest;
|
||||
import xyz.playedu.api.service.AdminUserService;
|
||||
@ -22,7 +23,7 @@ import java.util.HashMap;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/admin/v1/auth")
|
||||
@RequestMapping("/backend/v1/auth")
|
||||
public class LoginController {
|
||||
|
||||
@Autowired
|
||||
@ -57,8 +58,10 @@ public class LoginController {
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
public JsonResponse logout() {
|
||||
public JsonResponse logout() throws JwtLogoutException {
|
||||
jwtService.logout(RequestUtil.token(), SystemConstant.JWT_PRV_ADMIN_USER);
|
||||
return JsonResponse.success("success");
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package xyz.playedu.api.controller.admin;
|
||||
package xyz.playedu.api.controller.backend;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -12,7 +12,7 @@ import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/admin/v1/system")
|
||||
@RequestMapping("/backend/v1/system")
|
||||
public class SystemController {
|
||||
|
||||
@Autowired
|
@ -0,0 +1,63 @@
|
||||
package xyz.playedu.api.middleware;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import xyz.playedu.api.PlayEduThreadLocal;
|
||||
import xyz.playedu.api.bus.BackendBus;
|
||||
import xyz.playedu.api.constant.SystemConstant;
|
||||
import xyz.playedu.api.service.JWTService;
|
||||
import xyz.playedu.api.types.JWTPayload;
|
||||
import xyz.playedu.api.types.JsonResponse;
|
||||
import xyz.playedu.api.util.RequestUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AdminAuthMiddleware implements HandlerInterceptor {
|
||||
|
||||
@Autowired
|
||||
private JWTService jwtService;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
if (BackendBus.inUnAuthWhitelist(request.getRequestURI())) {
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
String token = RequestUtil.token();
|
||||
if (token.length() == 0) {
|
||||
responseTransform(response, 401, "请登录");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
JWTPayload payload = jwtService.parse(token, SystemConstant.JWT_PRV_ADMIN_USER);
|
||||
|
||||
// 用户信息写入context
|
||||
PlayEduThreadLocal.setAdminUserId(payload.getSub());
|
||||
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
} catch (Exception e) {
|
||||
responseTransform(response, 401, "请重新登录");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void responseTransform(HttpServletResponse response, int code, String msg) throws IOException {
|
||||
response.setStatus(code);
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.getWriter().print(JSON.toJSONString(JsonResponse.error(msg)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
PlayEduThreadLocal.remove();
|
||||
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
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();
|
||||
}
|
@ -2,6 +2,7 @@ package xyz.playedu.api.middleware;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Documented
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ImageCaptchaCheckMiddleware {
|
||||
|
@ -1,34 +0,0 @@
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,15 @@
|
||||
package xyz.playedu.api.service;
|
||||
|
||||
import xyz.playedu.api.exception.JwtLogoutException;
|
||||
import xyz.playedu.api.types.JWTPayload;
|
||||
import xyz.playedu.api.types.JwtToken;
|
||||
|
||||
public interface JWTService {
|
||||
JwtToken generate(Integer userId, String iss, String prv);
|
||||
|
||||
boolean isInBlack(String jti);
|
||||
|
||||
void logout(String token, String prv) throws JwtLogoutException;
|
||||
|
||||
JWTPayload parse(String token, String prv) throws JwtLogoutException;
|
||||
}
|
||||
|
@ -23,6 +23,18 @@ public class RequestUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String token() {
|
||||
HttpServletRequest request = RequestUtil.handler();
|
||||
if (request == null) {
|
||||
return "";
|
||||
}
|
||||
String token = request.getHeader("Authorization");
|
||||
if (token == null || token.length() == 0 || token.split(" ").length != 2) {
|
||||
return "";
|
||||
}
|
||||
return token.split(" ")[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取不带参请求URl
|
||||
* 示例: https://127.0.0.1:8082/api/system/menu/menus
|
||||
|
@ -42,5 +42,7 @@ playedu:
|
||||
key: "eJTJSLPv13fw9twbuPoeicypLqnSfYWL" #32个字符,加密key用来加密jwt的数据[运行本系统之前请务必修改]
|
||||
expire: 1296000 #token有效期[单位:秒,默认15天]
|
||||
cache-black-prefix: "jwt:blk:" #主动注销的token黑名单缓存前缀
|
||||
|
||||
# CORS
|
||||
cors:
|
||||
origins: "*"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user