清理归档下,已经迁移的逻辑

This commit is contained in:
YunaiV
2022-06-17 20:39:21 +08:00
parent e20600f0c2
commit ff18d2f30a
108 changed files with 0 additions and 4598 deletions

View File

@@ -1,71 +0,0 @@
package cn.iocoder.common.framework.exception;
import cn.iocoder.common.framework.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.common.framework.vo.CommonResult;
/**
* 全局异常 Exception
*/
public class GlobalException extends RuntimeException {
/**
* 全局错误码
*
* @see GlobalErrorCodeConstants
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细,内部调试错误
*
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
*/
private String detailMessage;
/**
* 空构造方法,避免反序列化问题
*/
public GlobalException() {
}
public GlobalException(ErrorCode errorCode) {
this.code = errorCode.getCode();
this.message = errorCode.getMessage();
}
public GlobalException(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getDetailMessage() {
return detailMessage;
}
public GlobalException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
public GlobalException setCode(Integer code) {
this.code = code;
return this;
}
public String getMessage() {
return message;
}
public GlobalException setMessage(String message) {
this.message = message;
return this;
}
}

View File

@@ -1,71 +0,0 @@
package cn.iocoder.common.framework.exception;
import cn.iocoder.common.framework.exception.enums.ServiceErrorCodeRange;
import cn.iocoder.common.framework.vo.CommonResult;
/**
* 业务逻辑异常 Exception
*/
public final class ServiceException extends RuntimeException {
/**
* 业务错误码
*
* @see ServiceErrorCodeRange
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细,内部调试错误
*
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
*/
private String detailMessage;
/**
* 空构造方法,避免反序列化问题
*/
public ServiceException() {
}
public ServiceException(ErrorCode errorCode) {
this.code = errorCode.getCode();
this.message = errorCode.getMessage();
}
public ServiceException(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getDetailMessage() {
return detailMessage;
}
public ServiceException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
public ServiceException setCode(Integer code) {
this.code = code;
return this;
}
public String getMessage() {
return message;
}
public ServiceException setMessage(String message) {
this.message = message;
return this;
}
}

View File

@@ -1,36 +0,0 @@
package cn.iocoder.common.framework.exception.enums;
import cn.iocoder.common.framework.exception.ErrorCode;
/**
* 全局错误码枚举
* 0-999 系统异常编码保留
*
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
* 虽然说HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
*/
public interface GlobalErrorCodeConstants {
ErrorCode SUCCESS = new ErrorCode(0, "成功");
// ========== 客户端错误段 ==========
ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到");
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
// ========== 服务端错误段 ==========
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
static boolean isMatch(Integer code) {
return code != null
&& code >= SUCCESS.getCode() && code <= UNKNOWN.getCode();
}
}

View File

@@ -1,47 +0,0 @@
package cn.iocoder.common.framework.exception.enums;
/**
* 业务异常的错误码区间,解决:解决各模块错误码定义,避免重复,在此只声明不做实际使用
*
* 一共 10 位,分成四段
*
* 第一段1 位,类型
* 1 - 业务级别异常
* x - 预留
* 第二段3 位,系统类型
* 001 - 用户系统
* 002 - 商品系统
* 003 - 订单系统
* 004 - 支付系统
* 005 - 优惠劵系统
* ... - ...
* 第三段3 位,模块
* 不限制规则。
* 一般建议,每个系统里面,可能有多个模块,可以再去做分段。以用户系统为例子:
* 001 - OAuth2 模块
* 002 - User 模块
* 003 - MobileCode 模块
* 第四段3 位,错误码
* 不限制规则。
* 一般建议,每个模块自增。
*
* @author Sin
* @time 2019-03-23 11:28
*/
public class ServiceErrorCodeRange {
// order 错误码区间 [1-000-001-000 ~ 1-000-002-000]
// user 错误码区间 [1-001-000-000 ~ 1-002-000-000)
// system-service 服务 => 错误码区间 [1-002-000-000 ~ 1-003-000-000)
// product 错误码区间 [1-003-000-000 ~ 1-004-000-000)
// pay 错误码区间 [1-004-000-000 ~ 1-005-000-000)
// cart 错误码区间 [1-005-000-000 ~ 1-006-000-000)
// promotion 错误码区间 [1-006-000-000 ~ 1-007-000-000)
}

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mall-security-annotations</artifactId>
</project>

View File

@@ -1,18 +0,0 @@
package cn.iocoder.security.annotations;
import java.lang.annotation.*;
/**
* 要求用户认证(登陆)注解。通过将该注解添加到 Controller 上,会自动校验用户是否登陆。
*
* 默认请求下,用户访问的 API 接口,无需登陆。主要的考虑是,
* 1. 需要用户登陆的接口,本身会获取在线用户的编号。如果不添加 @RequiresLogin 注解就会报错。
* 2. 大多数情况下,用户的 API 接口无需登陆。
*
* ps同样适用于管理员 Admin
*/
@Documented
@Target({ElementType.METHOD}) // 暂时不支持 ElementType.TYPE ,因为没有场景
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresAuthenticate {
}

View File

@@ -1,12 +0,0 @@
package cn.iocoder.security.annotations;
import java.lang.annotation.*;
/**
* 通过将该注解添加到 Controller 的方法上,声明无需进行登陆
*/
@Documented
@Target({ElementType.METHOD}) // 暂时不支持 ElementType.TYPE ,因为没有场景
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresNone {
}

View File

@@ -1,24 +0,0 @@
package cn.iocoder.security.annotations;
import java.lang.annotation.*;
/**
* 参考 Shiro @RequiresPermissions 设计 http://shiro.apache.org/static/1.3.2/apidocs/org/apache/shiro/authz/annotation/RequiresPermissions.html
*
* 通过将该注解添加到 Controller 的方法上,进行授权鉴定
*
* ps目前暂时只有管理员 Admin 使用到
*/
@Documented
@Target({ElementType.METHOD}) // 暂时不支持 ElementType.TYPE ,因为没有场景
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresPermissions {
/**
* 当有多个标识时,必须全部拥有权限,才可以操作
*
* @return 权限标识数组
*/
String[] value() default {};
}

View File

@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mall-spring-boot-starter-security-admin</artifactId>
<dependencies>
<!-- Mall 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>system-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Spring 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-web</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-security-annotations</artifactId>
</dependency>
<!-- RPC 相关 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,60 +0,0 @@
package cn.iocoder.mall.security.admin.config;
import cn.iocoder.mall.security.admin.core.interceptor.AdminDemoInterceptor;
import cn.iocoder.mall.security.admin.core.interceptor.AdminSecurityInterceptor;
import cn.iocoder.mall.web.config.CommonWebAutoConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@AutoConfigureAfter(CommonWebAutoConfiguration.class) // 在 CommonWebAutoConfiguration 之后自动配置,保证过滤器的顺序
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableConfigurationProperties(AdminSecurityProperties.class)
public class AdminSecurityAutoConfiguration implements WebMvcConfigurer {
private Logger logger = LoggerFactory.getLogger(getClass());
@Bean
@ConditionalOnMissingBean
public AdminSecurityProperties adminSecurityProperties() {
return new AdminSecurityProperties();
}
// ========== 拦截器相关 ==========
@Bean
public AdminSecurityInterceptor adminSecurityInterceptor() {
return new AdminSecurityInterceptor();
}
@Bean
public AdminDemoInterceptor adminDemoInterceptor() {
return new AdminDemoInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
AdminSecurityProperties properties = this.adminSecurityProperties();
// AdminSecurityInterceptor 拦截器
registry.addInterceptor(this.adminSecurityInterceptor())
.excludePathPatterns(properties.getIgnorePaths())
.excludePathPatterns(properties.getDefaultIgnorePaths());
logger.info("[addInterceptors][加载 AdminSecurityInterceptor 拦截器完成]");
// AdminDemoInterceptor 拦截器
if (Boolean.TRUE.equals(properties.getDemo())) {
registry.addInterceptor(this.adminDemoInterceptor())
.excludePathPatterns(properties.getIgnorePaths())
.excludePathPatterns(properties.getDefaultIgnorePaths());
logger.info("[addInterceptors][加载 AdminDemoInterceptor 拦截器完成]");
}
}
}

View File

@@ -1,59 +0,0 @@
package cn.iocoder.mall.security.admin.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("mall.security.admin")
public class AdminSecurityProperties {
private static final String[] DEFAULT_IGNORE_PATHS = new String[]{
// Swagger 相关
"/doc.html", "/swagger-resources", "/swagger-resources/**", "/webjars/**",
// Actuator 相关
};
/**
* 演示模式 - 默认值(关闭)
*/
private static final Boolean DEFAULT_DEMO = false;
/**
* 自定义忽略 Path
*/
private String[] ignorePaths = new String[0];
/**
* 默认忽略 Path
*/
private String[] defaultIgnorePaths = DEFAULT_IGNORE_PATHS;
/**
* 是否开启演示模式
*/
private Boolean demo = DEFAULT_DEMO;
public String[] getIgnorePaths() {
return ignorePaths;
}
public AdminSecurityProperties setIgnorePaths(String[] ignorePaths) {
this.ignorePaths = ignorePaths;
return this;
}
public String[] getDefaultIgnorePaths() {
return defaultIgnorePaths;
}
public AdminSecurityProperties setDefaultIgnorePaths(String[] defaultIgnorePaths) {
this.defaultIgnorePaths = defaultIgnorePaths;
return this;
}
public Boolean getDemo() {
return demo;
}
public AdminSecurityProperties setDemo(Boolean demo) {
this.demo = demo;
return this;
}
}

View File

@@ -1,18 +0,0 @@
package cn.iocoder.mall.security.admin.core.context;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* Admin Security 上下文
*/
@Data
@Accessors(chain = true)
public class AdminSecurityContext {
/**
* 管理员编号
*/
private Integer adminId;
}

View File

@@ -1,34 +0,0 @@
package cn.iocoder.mall.security.admin.core.context;
/**
* {@link AdminSecurityContext} Holder
*
* 参考 spring security 的 ThreadLocalSecurityContextHolderStrategy 类,简单实现。
*/
public class AdminSecurityContextHolder {
private static final ThreadLocal<AdminSecurityContext> SECURITY_CONTEXT = new ThreadLocal<>();
public static void setContext(AdminSecurityContext context) {
SECURITY_CONTEXT.set(context);
}
public static AdminSecurityContext getContext() {
AdminSecurityContext ctx = SECURITY_CONTEXT.get();
// 为空时,设置一个空的进去
if (ctx == null) {
ctx = new AdminSecurityContext();
SECURITY_CONTEXT.set(ctx);
}
return ctx;
}
public static void clear() {
SECURITY_CONTEXT.remove();
}
public static Integer getAdminId() {
return getContext().getAdminId();
}
}

View File

@@ -1,31 +0,0 @@
package cn.iocoder.mall.security.admin.core.interceptor;
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
import cn.iocoder.mall.security.admin.core.context.AdminSecurityContextHolder;
import cn.iocoder.mall.systemservice.enums.SystemErrorCodeConstants;
import org.springframework.http.HttpMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
/**
* Admin 演示拦截器
*
* 这是个比较“奇怪”的拦截器,用于演示的管理员账号,禁止使用 POST 请求,从而实现即达到阉割版的演示的效果,又避免影响了数据
*/
public class AdminDemoInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 当 Admin 编号等于 1 时,约定为演示账号
// TODO 芋艿,后续去优化
if (Objects.equals(AdminSecurityContextHolder.getAdminId(), 1)
&& request.getMethod().equalsIgnoreCase(HttpMethod.POST.toString())) {
throw ServiceExceptionUtil.exception(SystemErrorCodeConstants.PERMISSION_DEMO_PERMISSION_DENY);
}
return true;
}
}

View File

@@ -1,96 +0,0 @@
package cn.iocoder.mall.security.admin.core.interceptor;
import cn.iocoder.common.framework.enums.UserTypeEnum;
import cn.iocoder.common.framework.exception.GlobalException;
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.util.CollectionUtils;
import cn.iocoder.common.framework.util.HttpUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.security.admin.core.context.AdminSecurityContext;
import cn.iocoder.mall.security.admin.core.context.AdminSecurityContextHolder;
import cn.iocoder.mall.systemservice.rpc.oauth.OAuthFeign;
import cn.iocoder.mall.systemservice.rpc.oauth.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.mall.systemservice.rpc.permission.PermissionFeign;
import cn.iocoder.mall.systemservice.rpc.permission.dto.PermissionCheckDTO;
import cn.iocoder.mall.web.core.util.CommonWebUtil;
import cn.iocoder.security.annotations.RequiresNone;
import cn.iocoder.security.annotations.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import static cn.iocoder.common.framework.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED;
import static cn.iocoder.mall.systemservice.enums.SystemErrorCodeConstants.OAUTH_USER_TYPE_ERROR;
public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
@Autowired
private OAuthFeign oAuthFeign;
@Autowired
private PermissionFeign permissionFeign;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 获得访问令牌
Integer adminId = this.obtainAdminId(request);
// 校验认证
this.checkAuthentication((HandlerMethod) handler, adminId);
// 校验权限
this.checkPermission((HandlerMethod) handler, adminId);
return true;
}
private Integer obtainAdminId(HttpServletRequest request) {
String accessToken = HttpUtil.obtainAuthorization(request);
Integer adminId = null;
if (accessToken != null) {
CommonResult<OAuth2AccessTokenRespDTO> checkAccessTokenResult = oAuthFeign.checkAccessToken(accessToken);
checkAccessTokenResult.checkError();
// 校验用户类型正确
if (!UserTypeEnum.ADMIN.getValue().equals(checkAccessTokenResult.getData().getUserType())) {
throw ServiceExceptionUtil.exception(OAUTH_USER_TYPE_ERROR);
}
// 获得用户编号
adminId = checkAccessTokenResult.getData().getUserId();
// 设置到 Request 中
CommonWebUtil.setUserId(request, adminId);
CommonWebUtil.setUserType(request, UserTypeEnum.ADMIN.getValue());
// 设置到
AdminSecurityContext adminSecurityContext = new AdminSecurityContext().setAdminId(adminId);
AdminSecurityContextHolder.setContext(adminSecurityContext);
}
return adminId;
}
private void checkAuthentication(HandlerMethod handlerMethod, Integer adminId) {
boolean requiresAuthenticate = !handlerMethod.hasMethodAnnotation(RequiresNone.class); // 对于 ADMIN 来说,默认需登录
if (requiresAuthenticate && adminId == null) {
throw new GlobalException(UNAUTHORIZED);
}
}
private void checkPermission(HandlerMethod handlerMethod, Integer adminId) {
RequiresPermissions requiresPermissions = handlerMethod.getMethodAnnotation(RequiresPermissions.class);
if (requiresPermissions == null) {
return;
}
String[] permissions = requiresPermissions.value();
if (CollectionUtils.isEmpty(permissions)) {
return;
}
// 权限验证
permissionFeign.checkPermission(new PermissionCheckDTO().setAdminId(adminId).setPermissions(Arrays.asList(permissions)))
.checkError();
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// 清空 SecurityContext
AdminSecurityContextHolder.clear();
}
}

View File

@@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.mall.security.admin.config.AdminSecurityAutoConfiguration

View File

@@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mall-spring-boot-starter-security-user</artifactId>
<dependencies>
<!-- Mall 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>system-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Spring 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-security-annotations</artifactId>
</dependency>
<!-- RPC 相关 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,47 +0,0 @@
package cn.iocoder.mall.security.user.config;
import cn.iocoder.mall.security.user.core.interceptor.UserSecurityInterceptor;
import cn.iocoder.mall.web.config.CommonWebAutoConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@AutoConfigureAfter(CommonWebAutoConfiguration.class) // 在 CommonWebAutoConfiguration 之后自动配置,保证过滤器的顺序
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableConfigurationProperties(UserSecurityProperties.class)
public class UserSecurityAutoConfiguration implements WebMvcConfigurer {
private Logger logger = LoggerFactory.getLogger(getClass());
@Bean
@ConditionalOnMissingBean
public UserSecurityProperties userSecurityProperties() {
return new UserSecurityProperties();
}
// ========== 拦截器相关 ==========
@Bean
public UserSecurityInterceptor userSecurityInterceptor() {
return new UserSecurityInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
UserSecurityProperties properties = this.userSecurityProperties();
// UserSecurityInterceptor 拦截器
registry.addInterceptor(this.userSecurityInterceptor())
.excludePathPatterns(properties.getIgnorePaths())
.excludePathPatterns(properties.getDefaultIgnorePaths());;
logger.info("[addInterceptors][加载 UserSecurityInterceptor 拦截器完成]");
}
}

View File

@@ -1,41 +0,0 @@
package cn.iocoder.mall.security.user.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("mall.security.user")
public class UserSecurityProperties {
private static final String[] DEFAULT_IGNORE_PATHS = new String[]{
// Swagger 相关
"/doc.html", "/swagger-resources", "/swagger-resources/**", "/webjars/**",
// Actuator 相关
};
/**
* 自定义忽略 Path
*/
private String[] ignorePaths = new String[0];
/**
* 默认忽略 Path
*/
private String[] defaultIgnorePaths = DEFAULT_IGNORE_PATHS;
public String[] getIgnorePaths() {
return ignorePaths;
}
public UserSecurityProperties setIgnorePaths(String[] ignorePaths) {
this.ignorePaths = ignorePaths;
return this;
}
public String[] getDefaultIgnorePaths() {
return defaultIgnorePaths;
}
public UserSecurityProperties setDefaultIgnorePaths(String[] defaultIgnorePaths) {
this.defaultIgnorePaths = defaultIgnorePaths;
return this;
}
}

View File

@@ -1,18 +0,0 @@
package cn.iocoder.mall.security.user.core.context;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* User Security 上下文
*/
@Data
@Accessors(chain = true)
public class UserSecurityContext {
/**
* 用户编号
*/
private Integer userId;
}

View File

@@ -1,35 +0,0 @@
package cn.iocoder.mall.security.user.core.context;
/**
* {@link UserSecurityContext} Holder
*
* 参考 spring security 的 ThreadLocalSecurityContextHolderStrategy 类,简单实现。
*/
public class UserSecurityContextHolder {
private static final ThreadLocal<UserSecurityContext> SECURITY_CONTEXT = new ThreadLocal<UserSecurityContext>();
public static void setContext(UserSecurityContext context) {
SECURITY_CONTEXT.set(context);
}
public static UserSecurityContext getContext() {
UserSecurityContext ctx = SECURITY_CONTEXT.get();
// 为空时,设置一个空的进去
if (ctx == null) {
ctx = new UserSecurityContext();
SECURITY_CONTEXT.set(ctx);
}
return ctx;
}
public static Integer getUserId() {
UserSecurityContext ctx = SECURITY_CONTEXT.get();
return ctx != null ? ctx.getUserId() : null;
}
public static void clear() {
SECURITY_CONTEXT.remove();
}
}

View File

@@ -1,77 +0,0 @@
package cn.iocoder.mall.security.user.core.interceptor;
import cn.iocoder.common.framework.enums.UserTypeEnum;
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.util.HttpUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.security.user.core.context.UserSecurityContext;
import cn.iocoder.mall.security.user.core.context.UserSecurityContextHolder;
import cn.iocoder.mall.systemservice.rpc.oauth.OAuthFeign;
import cn.iocoder.mall.systemservice.rpc.oauth.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.mall.web.core.util.CommonWebUtil;
import cn.iocoder.security.annotations.RequiresAuthenticate;
import cn.iocoder.security.annotations.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static cn.iocoder.common.framework.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED;
import static cn.iocoder.mall.systemservice.enums.SystemErrorCodeConstants.OAUTH_USER_TYPE_ERROR;
public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
@Autowired
private OAuthFeign oAuthFeign;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 获得访问令牌
Integer userId = this.obtainUserId(request);
// 校验认证
this.checkAuthentication((HandlerMethod) handler, userId);
return true;
}
private Integer obtainUserId(HttpServletRequest request) {
String accessToken = HttpUtil.obtainAuthorization(request);
Integer userId = null;
if (accessToken != null) {
CommonResult<OAuth2AccessTokenRespDTO> checkAccessTokenResult = oAuthFeign.checkAccessToken(accessToken);
checkAccessTokenResult.checkError();
// 校验用户类型正确
if (!UserTypeEnum.USER.getValue().equals(checkAccessTokenResult.getData().getUserType())) {
throw ServiceExceptionUtil.exception(OAUTH_USER_TYPE_ERROR);
}
// 获得用户编号
userId = checkAccessTokenResult.getData().getUserId();
// 设置到 Request 中
CommonWebUtil.setUserId(request, userId);
CommonWebUtil.setUserType(request, UserTypeEnum.USER.getValue());
// 设置到
UserSecurityContext userSecurityContext = new UserSecurityContext().setUserId(userId);
UserSecurityContextHolder.setContext(userSecurityContext);
}
return userId;
}
private void checkAuthentication(HandlerMethod handlerMethod, Integer userId) {
boolean requiresAuthenticate = false; // 对于 USER 来说,默认无需登录
if (handlerMethod.hasMethodAnnotation(RequiresAuthenticate.class)
|| handlerMethod.hasMethodAnnotation(RequiresPermissions.class)) { // 如果需要权限验证,也认为需要认证
requiresAuthenticate = true;
}
if (requiresAuthenticate && userId == null) {
throw ServiceExceptionUtil.exception(UNAUTHORIZED);
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// 清空 SecurityContext
UserSecurityContextHolder.clear();
}
}

View File

@@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.mall.security.user.config.UserSecurityAutoConfiguration