mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-09-24 06:16:39 +08:00
sa-token
This commit is contained in:
parent
0d17270b11
commit
54d8d9489a
@ -0,0 +1,43 @@
|
|||||||
|
package net.lab1024.sa.admin.config;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||||
|
import cn.dev33.satoken.router.SaRouter;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import net.lab1024.sa.common.config.UrlConfig;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.DependsOn;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sa-token 配置
|
||||||
|
*
|
||||||
|
* @author Turbolisten
|
||||||
|
* @date 2023/7/13 16:57
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class SaTokenConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册 Sa-Token 拦截器,定义详细认证规则
|
||||||
|
*
|
||||||
|
* @param registry
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
SaInterceptor interceptor = new SaInterceptor(handler -> {
|
||||||
|
|
||||||
|
// 每个路由 都做为一个权限点
|
||||||
|
UrlConfig.URL_LIST.forEach(url -> SaRouter.match(url, r -> StpUtil.checkPermission(url)));
|
||||||
|
|
||||||
|
});
|
||||||
|
// 关闭注解鉴权 只做路由拦截校验
|
||||||
|
interceptor.isAnnotation(false);
|
||||||
|
registry.addInterceptor(interceptor).addPathPatterns("/**");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -2,17 +2,17 @@ package net.lab1024.sa.admin.interceptor;
|
|||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.hutool.core.convert.NumberWithFormat;
|
import cn.hutool.core.convert.NumberWithFormat;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import net.lab1024.sa.common.common.domain.RequestUser;
|
import net.lab1024.sa.common.common.domain.RequestUser;
|
||||||
import net.lab1024.sa.common.common.enumeration.UserTypeEnum;
|
import net.lab1024.sa.common.common.enumeration.UserTypeEnum;
|
||||||
import net.lab1024.sa.common.common.interceptor.AbstractInterceptor;
|
import net.lab1024.sa.common.common.interceptor.AbstractInterceptor;
|
||||||
import net.lab1024.sa.common.common.util.SmartEnumUtil;
|
import net.lab1024.sa.common.common.util.SmartEnumUtil;
|
||||||
import net.lab1024.sa.common.handler.GlobalExceptionHandler;
|
|
||||||
import net.lab1024.sa.common.module.support.token.TokenService;
|
import net.lab1024.sa.common.module.support.token.TokenService;
|
||||||
import org.apache.commons.lang3.math.NumberUtils;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* admin 拦截器
|
* admin 拦截器
|
||||||
@ -24,30 +24,22 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
public class AdminInterceptor extends AbstractInterceptor {
|
public class AdminInterceptor extends AbstractInterceptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开发环境 方便调试 默认 user id 1
|
* 配置拦截路径
|
||||||
* 可以根据id 查询实际用户数据
|
|
||||||
*
|
*
|
||||||
* @param token
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public RequestUser getDevRequestUser(String token) {
|
public List<String> pathPatterns() {
|
||||||
long userId = NumberUtils.toLong(token, 1L);
|
return Lists.newArrayList("/**");
|
||||||
RequestUser requestUser = new RequestUser();
|
|
||||||
requestUser.setUserId(userId);
|
|
||||||
requestUser.setUserName("dev");
|
|
||||||
requestUser.setUserType(UserTypeEnum.ADMIN_EMPLOYEE);
|
|
||||||
return requestUser;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RequestUser checkTokenAndGetUser() {
|
public void checkSaToken() {
|
||||||
/**
|
|
||||||
* 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
|
|
||||||
* 已在全局异常处理
|
|
||||||
* @see GlobalExceptionHandler#handlerNotLoginException
|
|
||||||
*/
|
|
||||||
StpUtil.checkLogin();
|
StpUtil.checkLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestUser getRequestUser() {
|
||||||
// 获取额外数据
|
// 获取额外数据
|
||||||
Integer userType = ((NumberWithFormat) StpUtil.getExtra(TokenService.EXTRA_KEY_USER_TYPE)).intValue();
|
Integer userType = ((NumberWithFormat) StpUtil.getExtra(TokenService.EXTRA_KEY_USER_TYPE)).intValue();
|
||||||
UserTypeEnum userTypeEnum = SmartEnumUtil.getEnumByValue(userType, UserTypeEnum.class);
|
UserTypeEnum userTypeEnum = SmartEnumUtil.getEnumByValue(userType, UserTypeEnum.class);
|
||||||
@ -62,25 +54,13 @@ public class AdminInterceptor extends AbstractInterceptor {
|
|||||||
return requestUser;
|
return requestUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 配置拦截路径
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String[] pathPatterns() {
|
|
||||||
return new String[]{"/**"};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
boolean isHandle = super.preHandle(request, response, handler);
|
boolean isHandle = super.preHandle(request, response, handler);
|
||||||
if (!isHandle) {
|
if (!isHandle) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// 如有业务需处理 写在此处
|
||||||
// TODO listen 校验权限
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.lab1024.sa.admin.module.system.login.controller;
|
package net.lab1024.sa.admin.module.system.login.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
import cn.hutool.extra.servlet.ServletUtil;
|
import cn.hutool.extra.servlet.ServletUtil;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
@ -12,6 +13,7 @@ import net.lab1024.sa.common.common.constant.RequestHeaderConst;
|
|||||||
import net.lab1024.sa.common.common.domain.ResponseDTO;
|
import net.lab1024.sa.common.common.domain.ResponseDTO;
|
||||||
import net.lab1024.sa.common.common.util.SmartRequestUtil;
|
import net.lab1024.sa.common.common.util.SmartRequestUtil;
|
||||||
import net.lab1024.sa.common.module.support.captcha.domain.CaptchaVO;
|
import net.lab1024.sa.common.module.support.captcha.domain.CaptchaVO;
|
||||||
|
import org.checkerframework.checker.units.qual.N;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -85,4 +87,11 @@ public class LoginController {
|
|||||||
return loginService.getCaptcha();
|
return loginService.getCaptcha();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO listen
|
||||||
|
@NoNeedLogin
|
||||||
|
@ApiOperation("测试权限 @listen")
|
||||||
|
@GetMapping("/listen/test")
|
||||||
|
public ResponseDTO<String> test() {
|
||||||
|
return ResponseDTO.ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ public enum UserErrorCode implements ErrorCode {
|
|||||||
|
|
||||||
REPEAT_SUBMIT(30004, "亲~您操作的太快了,请稍等下再操作~"),
|
REPEAT_SUBMIT(30004, "亲~您操作的太快了,请稍等下再操作~"),
|
||||||
|
|
||||||
NO_PERMISSION(30005, "对不起,您无法访问此资源哦~"),
|
NO_PERMISSION(30005, "对不起,您无法访问此内容哦~"),
|
||||||
|
|
||||||
DEVELOPING(30006, "系統正在紧急开发中,敬请期待~"),
|
DEVELOPING(30006, "系統正在紧急开发中,敬请期待~"),
|
||||||
|
|
||||||
|
@ -18,9 +18,6 @@ public class RequestUrlVO {
|
|||||||
@ApiModelProperty("注释说明")
|
@ApiModelProperty("注释说明")
|
||||||
private String comment;
|
private String comment;
|
||||||
|
|
||||||
@ApiModelProperty("controller.method")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@ApiModelProperty("url")
|
@ApiModelProperty("url")
|
||||||
private String url;
|
private String url;
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,17 @@
|
|||||||
package net.lab1024.sa.common.common.interceptor;
|
package net.lab1024.sa.common.common.interceptor;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.exception.NotLoginException;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import net.lab1024.sa.common.common.annoation.NoNeedLogin;
|
import net.lab1024.sa.common.common.annoation.NoNeedLogin;
|
||||||
import net.lab1024.sa.common.common.code.UserErrorCode;
|
import net.lab1024.sa.common.common.code.UserErrorCode;
|
||||||
import net.lab1024.sa.common.common.constant.RequestHeaderConst;
|
|
||||||
import net.lab1024.sa.common.common.constant.StringConst;
|
|
||||||
import net.lab1024.sa.common.common.domain.RequestUser;
|
import net.lab1024.sa.common.common.domain.RequestUser;
|
||||||
import net.lab1024.sa.common.common.domain.ResponseDTO;
|
import net.lab1024.sa.common.common.domain.ResponseDTO;
|
||||||
import net.lab1024.sa.common.common.domain.SystemEnv;
|
|
||||||
import net.lab1024.sa.common.common.enumeration.SystemEnvEnum;
|
|
||||||
import net.lab1024.sa.common.common.util.SmartRequestUtil;
|
import net.lab1024.sa.common.common.util.SmartRequestUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.math.NumberUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
@ -24,50 +19,42 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 抽象拦截器
|
* 抽象拦截器
|
||||||
* 如果有额外的拦截处理 可以继承此类
|
* 只校验了登录处理
|
||||||
|
* 自定义的拦截器 可以继承此类
|
||||||
*
|
*
|
||||||
* @Author 1024创新实验室: 罗伊
|
* @author huke
|
||||||
* @Date 2021-10-09 20:56:14
|
* @date 2023-07-12 21:56:14
|
||||||
* @Wechat zhuoda1024
|
|
||||||
* @Email lab1024@163.com
|
|
||||||
* @Copyright 1024创新实验室 ( https://1024lab.net )
|
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractInterceptor implements HandlerInterceptor {
|
public abstract class AbstractInterceptor implements HandlerInterceptor {
|
||||||
|
/**
|
||||||
@Autowired
|
* 校验 token
|
||||||
private SystemEnv systemEnv;
|
*/
|
||||||
|
public abstract void checkSaToken();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token获取用户信息
|
* Token 获取当前请求用户信息
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public abstract RequestUser checkTokenAndGetUser();
|
public abstract RequestUser getRequestUser();
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 dev 开发用户
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public abstract RequestUser getDevRequestUser(String token);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拦截路径
|
* 拦截路径
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public abstract String[] pathPatterns();
|
public abstract List<String> pathPatterns();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 忽略的url集合
|
* 忽略的url集合
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected List<String> getIgnoreUrlList() {
|
public List<String> getIgnoreUrlList() {
|
||||||
List<String> ignoreUrlList = Lists.newArrayList();
|
List<String> ignoreUrlList = Lists.newArrayList();
|
||||||
ignoreUrlList.add("/swagger-ui.html");
|
ignoreUrlList.add("/swagger-ui.html");
|
||||||
ignoreUrlList.add("/swagger-resources/**");
|
ignoreUrlList.add("/swagger-resources/**");
|
||||||
@ -78,7 +65,7 @@ public abstract class AbstractInterceptor implements HandlerInterceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拦截服务器端响应处理ajax请求返回结果
|
* 拦截处理登录 token
|
||||||
*
|
*
|
||||||
* @param request
|
* @param request
|
||||||
* @param response
|
* @param response
|
||||||
@ -89,61 +76,62 @@ public abstract class AbstractInterceptor implements HandlerInterceptor {
|
|||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
// OPTIONS请求直接return
|
// OPTIONS请求直接return
|
||||||
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
|
if (StringUtils.equalsIgnoreCase(HttpMethod.OPTIONS.name(), request.getMethod())) {
|
||||||
response.setStatus(HttpStatus.NO_CONTENT.value());
|
response.setStatus(HttpStatus.NO_CONTENT.value());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isHandler = handler instanceof HandlerMethod;
|
boolean isHandler = handler instanceof HandlerMethod;
|
||||||
if (!isHandler) {
|
if (!isHandler) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//放行的Uri前缀
|
// 校验 token 获取当前请求用户信息
|
||||||
String uri = request.getRequestURI();
|
ResponseDTO<RequestUser> res = this.checkTokenAndGetUser();
|
||||||
String contextPath = request.getContextPath();
|
if (res.getOk()) {
|
||||||
String target = uri.replaceFirst(contextPath, StringConst.EMPTY);
|
SmartRequestUtil.setUser(res.getData());
|
||||||
if (this.contain(this.getIgnoreUrlList(), target)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// 检查是否包含 token
|
// 不需要登录
|
||||||
String xRequestToken = request.getParameter(RequestHeaderConst.TOKEN);
|
|
||||||
String xHeaderToken = request.getHeader(RequestHeaderConst.TOKEN);
|
|
||||||
String xAccessToken = StringUtils.isNotBlank(xRequestToken) ? xRequestToken : xHeaderToken;
|
|
||||||
// 包含token 则获取用户信息 并保存
|
|
||||||
if (StringUtils.isNotBlank(xAccessToken)) {
|
|
||||||
// TODO listen 待处理有token 已失效的情况
|
|
||||||
RequestUser requestUser;
|
|
||||||
// 开发环境 token 处理 不需要的话 可以去掉
|
|
||||||
if (SystemEnvEnum.DEV == systemEnv.getCurrentEnv() && NumberUtils.isDigits(xAccessToken)) {
|
|
||||||
requestUser = this.getDevRequestUser(xAccessToken);
|
|
||||||
} else {
|
|
||||||
requestUser = this.checkTokenAndGetUser();
|
|
||||||
}
|
|
||||||
SmartRequestUtil.setUser(requestUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 是否需要登录
|
|
||||||
NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class);
|
NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class);
|
||||||
if (null != noNeedLogin) {
|
if (null != noNeedLogin) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (StringUtils.isBlank(xAccessToken)) {
|
this.outputResult(response, res);
|
||||||
this.outputResult(response, ResponseDTO.error(UserErrorCode.LOGIN_STATE_INVALID));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean contain(List<String> ignores, String uri) {
|
/**
|
||||||
if (CollectionUtils.isEmpty(ignores)) {
|
* 校验 sa token
|
||||||
return false;
|
* 判断 sa-token 未登录场景值
|
||||||
}
|
* 自己根据业务在下面 switch 添加分支判断
|
||||||
for (String ignoreUrl : ignores) {
|
* NotLoginException.NOT_TOKEN 无token
|
||||||
if (uri.startsWith(ignoreUrl)) {
|
* NotLoginException.INVALID_TOKEN token无效
|
||||||
return true;
|
* NotLoginException.TOKEN_TIMEOUT token过期
|
||||||
|
* NotLoginException.NO_PREFIX token缺少前缀
|
||||||
|
* NotLoginException.KICK_OUT 已被踢下线
|
||||||
|
* NotLoginException.TOKEN_FREEZE 已被冻结
|
||||||
|
* <p>
|
||||||
|
* ps :之所以没有在全局异常里处理 是因为后续还有操作
|
||||||
|
*/
|
||||||
|
public ResponseDTO<RequestUser> checkTokenAndGetUser() {
|
||||||
|
try {
|
||||||
|
/**
|
||||||
|
* sa-token 会从当前请求header or body 中获取token
|
||||||
|
* 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
|
||||||
|
*/
|
||||||
|
this.checkSaToken();
|
||||||
|
} catch (NotLoginException e) {
|
||||||
|
switch (e.getType()) {
|
||||||
|
case NotLoginException.BE_REPLACED:
|
||||||
|
// token 已被顶下线
|
||||||
|
return ResponseDTO.error(UserErrorCode.LOGIN_FROM_OTHER);
|
||||||
|
// case NotLoginException.TOKEN_FREEZE:
|
||||||
|
// case NotLoginException.KICK_OUT:
|
||||||
|
default:
|
||||||
|
return ResponseDTO.error(UserErrorCode.LOGIN_STATE_INVALID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
RequestUser requestUser = this.getRequestUser();
|
||||||
|
return ResponseDTO.ok(requestUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,13 +143,13 @@ public abstract class AbstractInterceptor implements HandlerInterceptor {
|
|||||||
*/
|
*/
|
||||||
private void outputResult(HttpServletResponse response, ResponseDTO responseDTO) throws IOException {
|
private void outputResult(HttpServletResponse response, ResponseDTO responseDTO) throws IOException {
|
||||||
String msg = JSONObject.toJSONString(responseDTO);
|
String msg = JSONObject.toJSONString(responseDTO);
|
||||||
response.setContentType("application/json;charset=UTF-8");
|
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||||
response.getWriter().write(msg);
|
response.getWriter().write(msg);
|
||||||
response.flushBuffer();
|
response.flushBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||||
SmartRequestUtil.remove();
|
SmartRequestUtil.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ public class MvcConfig implements WebMvcConfigurer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
interceptorList.forEach(e -> {
|
interceptorList.forEach(e -> {
|
||||||
registry.addInterceptor(e).addPathPatterns(e.pathPatterns());
|
registry.addInterceptor(e).addPathPatterns(e.pathPatterns()).excludePathPatterns(e.getIgnoreUrlList());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,126 @@
|
|||||||
|
package net.lab1024.sa.common.config;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.lab1024.sa.common.common.annoation.NoNeedLogin;
|
||||||
|
import net.lab1024.sa.common.common.domain.RequestUrlVO;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* description
|
||||||
|
*
|
||||||
|
* @author Turbolisten
|
||||||
|
* @date 2023/7/13 17:42
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
public class UrlConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||||
|
|
||||||
|
public static List<String> URL_LIST = Lists.newArrayList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取每个方法的请求路径
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Map<Method, Set<String>> methodUrlMap() {
|
||||||
|
Map<Method, Set<String>> methodUrlMap = Maps.newHashMap();
|
||||||
|
// 获取url与类和方法的对应信息
|
||||||
|
Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
|
||||||
|
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : map.entrySet()) {
|
||||||
|
RequestMappingInfo requestMappingInfo = entry.getKey();
|
||||||
|
Set<String> urls = requestMappingInfo.getPatternsCondition().getPatterns();
|
||||||
|
if (CollectionUtils.isEmpty(urls)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
HandlerMethod handlerMethod = entry.getValue();
|
||||||
|
methodUrlMap.put(handlerMethod.getMethod(), urls);
|
||||||
|
}
|
||||||
|
return methodUrlMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要进行url权限校验的方法
|
||||||
|
*
|
||||||
|
* @param methodUrlMap
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public List<RequestUrlVO> authUrl(Map<Method, Set<String>> methodUrlMap) {
|
||||||
|
List<RequestUrlVO> authUrlList = Lists.newArrayList();
|
||||||
|
for (Map.Entry<Method, Set<String>> entry : methodUrlMap.entrySet()) {
|
||||||
|
Method method = entry.getKey();
|
||||||
|
// 忽略权限
|
||||||
|
SaIgnore ignore = method.getAnnotation(SaIgnore.class);
|
||||||
|
if (null != ignore) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<RequestUrlVO> requestUrlList = this.buildRequestUrl(method, entry.getValue());
|
||||||
|
authUrlList.addAll(requestUrlList);
|
||||||
|
}
|
||||||
|
log.info("需要权限校验的URL:{}", authUrlList.stream().map(RequestUrlVO::getUrl).collect(Collectors.toList()));
|
||||||
|
return authUrlList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<RequestUrlVO> buildRequestUrl(Method method, Set<String> urlSet) {
|
||||||
|
List<RequestUrlVO> requestUrlList = Lists.newArrayList();
|
||||||
|
if (CollectionUtils.isEmpty(urlSet)) {
|
||||||
|
return requestUrlList;
|
||||||
|
}
|
||||||
|
// swagger api 说明
|
||||||
|
String methodComment = null;
|
||||||
|
ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
|
||||||
|
if (apiOperation != null) {
|
||||||
|
methodComment = apiOperation.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String url : urlSet) {
|
||||||
|
RequestUrlVO requestUrlVO = new RequestUrlVO();
|
||||||
|
requestUrlVO.setUrl(url);
|
||||||
|
requestUrlVO.setComment(methodComment);
|
||||||
|
requestUrlList.add(requestUrlVO);
|
||||||
|
|
||||||
|
URL_LIST.add(url);
|
||||||
|
}
|
||||||
|
return requestUrlList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取无需登录可以匿名访问的url信息
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public List<String> noNeedLoginUrlList(Map<Method, Set<String>> methodUrlMap) {
|
||||||
|
List<String> noNeedLoginUrlList = Lists.newArrayList();
|
||||||
|
for (Map.Entry<Method, Set<String>> entry : methodUrlMap.entrySet()) {
|
||||||
|
Method method = entry.getKey();
|
||||||
|
NoNeedLogin noNeedLogin = method.getAnnotation(NoNeedLogin.class);
|
||||||
|
if (null == noNeedLogin) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
noNeedLoginUrlList.addAll(entry.getValue());
|
||||||
|
}
|
||||||
|
log.info("不需要登录的URL:{}", noNeedLoginUrlList);
|
||||||
|
return noNeedLoginUrlList;
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
* @date: 2023/7/12 20:46
|
* @date: 2023/7/12 20:46
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SaTokenConfig {
|
public class SaTokenCommonConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 整合 jwt
|
* 整合 jwt
|
@ -1,11 +1,12 @@
|
|||||||
package net.lab1024.sa.common.handler;
|
package net.lab1024.sa.common.handler;
|
||||||
|
|
||||||
import cn.dev33.satoken.exception.NotLoginException;
|
import cn.dev33.satoken.exception.NotPermissionException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.lab1024.sa.common.common.code.SystemErrorCode;
|
import net.lab1024.sa.common.common.code.SystemErrorCode;
|
||||||
import net.lab1024.sa.common.common.code.UserErrorCode;
|
import net.lab1024.sa.common.common.code.UserErrorCode;
|
||||||
import net.lab1024.sa.common.common.domain.ResponseDTO;
|
import net.lab1024.sa.common.common.domain.ResponseDTO;
|
||||||
import net.lab1024.sa.common.common.domain.SystemEnv;
|
import net.lab1024.sa.common.common.domain.SystemEnv;
|
||||||
|
import net.lab1024.sa.common.common.enumeration.SystemEnvEnum;
|
||||||
import net.lab1024.sa.common.common.exception.BusinessException;
|
import net.lab1024.sa.common.common.exception.BusinessException;
|
||||||
import org.springframework.beans.TypeMismatchException;
|
import org.springframework.beans.TypeMismatchException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -37,7 +38,7 @@ import java.util.stream.Collectors;
|
|||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SystemEnv systemEnvironment;
|
private SystemEnv systemEnv;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* json 格式错误 缺少请求体
|
* json 格式错误 缺少请求体
|
||||||
@ -45,7 +46,7 @@ public class GlobalExceptionHandler {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ExceptionHandler({HttpMessageNotReadableException.class})
|
@ExceptionHandler({HttpMessageNotReadableException.class})
|
||||||
public ResponseDTO<?> jsonFormatExceptionHandler(Exception e) {
|
public ResponseDTO<?> jsonFormatExceptionHandler(Exception e) {
|
||||||
if (!systemEnvironment.isProd()) {
|
if (!systemEnv.isProd()) {
|
||||||
log.error("全局JSON格式错误异常,URL:{}", getCurrentRequestUrl(), e);
|
log.error("全局JSON格式错误异常,URL:{}", getCurrentRequestUrl(), e);
|
||||||
}
|
}
|
||||||
return ResponseDTO.error(UserErrorCode.PARAM_ERROR, "参数JSON格式错误");
|
return ResponseDTO.error(UserErrorCode.PARAM_ERROR, "参数JSON格式错误");
|
||||||
@ -57,7 +58,7 @@ public class GlobalExceptionHandler {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ExceptionHandler({TypeMismatchException.class, BindException.class})
|
@ExceptionHandler({TypeMismatchException.class, BindException.class})
|
||||||
public ResponseDTO<?> paramExceptionHandler(Exception e) {
|
public ResponseDTO<?> paramExceptionHandler(Exception e) {
|
||||||
if (!systemEnvironment.isProd()) {
|
if (!systemEnv.isProd()) {
|
||||||
log.error("全局参数异常,URL:{}", getCurrentRequestUrl(), e);
|
log.error("全局参数异常,URL:{}", getCurrentRequestUrl(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,38 +84,26 @@ public class GlobalExceptionHandler {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ExceptionHandler(BusinessException.class)
|
@ExceptionHandler(BusinessException.class)
|
||||||
public ResponseDTO<?> businessExceptionHandler(BusinessException e) {
|
public ResponseDTO<?> businessExceptionHandler(BusinessException e) {
|
||||||
if (!systemEnvironment.isProd()) {
|
if (!systemEnv.isProd()) {
|
||||||
log.error("全局业务异常,URL:{}", getCurrentRequestUrl(), e);
|
log.error("全局业务异常,URL:{}", getCurrentRequestUrl(), e);
|
||||||
}
|
}
|
||||||
return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, e.getMessage());
|
return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sa-token 登录异常处理
|
* sa-token 权限异常处理
|
||||||
*
|
*
|
||||||
* @param nle
|
* @param e
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ExceptionHandler(NotLoginException.class)
|
@ExceptionHandler(NotPermissionException.class)
|
||||||
public ResponseDTO<String> handlerNotLoginException(NotLoginException nle) {
|
public ResponseDTO<String> permissionException(NotPermissionException e) {
|
||||||
/**
|
// 开发环境 方便调试
|
||||||
* 判断场景值 自己根据业务在下面 switch 添加分支判断
|
if (SystemEnvEnum.PROD != systemEnv.getCurrentEnv()) {
|
||||||
* NotLoginException.NOT_TOKEN 无token
|
return ResponseDTO.error(UserErrorCode.NO_PERMISSION, e.getMessage());
|
||||||
* NotLoginException.INVALID_TOKEN token无效
|
|
||||||
* NotLoginException.TOKEN_TIMEOUT token过期
|
|
||||||
* NotLoginException.NO_PREFIX token缺少前缀
|
|
||||||
* NotLoginException.KICK_OUT 已被踢下线
|
|
||||||
* NotLoginException.TOKEN_FREEZE 已被冻结
|
|
||||||
*/
|
|
||||||
switch (nle.getType()) {
|
|
||||||
case NotLoginException.BE_REPLACED:
|
|
||||||
// token 已被顶下线
|
|
||||||
return ResponseDTO.error(UserErrorCode.LOGIN_FROM_OTHER);
|
|
||||||
default:
|
|
||||||
return ResponseDTO.error(UserErrorCode.LOGIN_STATE_INVALID);
|
|
||||||
}
|
}
|
||||||
|
return ResponseDTO.error(UserErrorCode.NO_PERMISSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,7 +116,7 @@ public class GlobalExceptionHandler {
|
|||||||
@ExceptionHandler(Throwable.class)
|
@ExceptionHandler(Throwable.class)
|
||||||
public ResponseDTO<?> errorHandler(Throwable e) {
|
public ResponseDTO<?> errorHandler(Throwable e) {
|
||||||
log.error("捕获全局异常,URL:{}", getCurrentRequestUrl(), e);
|
log.error("捕获全局异常,URL:{}", getCurrentRequestUrl(), e);
|
||||||
return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, systemEnvironment.isProd() ? null : e.toString());
|
return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, systemEnv.isProd() ? null : e.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,11 +56,11 @@ public class TokenService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String generateLoginId(Long userId, UserTypeEnum userType) {
|
public static String generateLoginId(Long userId, UserTypeEnum userType) {
|
||||||
return userType.getValue() + StringConst.UNDERLINE + userId;
|
return userType.getValue() + StringConst.HORIZONTAL + userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Long getUserId(String loginId) {
|
public static Long getUserId(String loginId) {
|
||||||
return Long.valueOf(loginId.substring(loginId.indexOf(StringConst.UNDERLINE) + 1));
|
return Long.valueOf(loginId.substring(loginId.indexOf(StringConst.HORIZONTAL) + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user