sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/annotation/EnableCustomConfig.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableCustomConfig.java @@ -1,31 +1,31 @@ package com.ruoyi.common.security.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.Import; import org.springframework.scheduling.annotation.EnableAsync; import com.ruoyi.common.security.config.ApplicationConfig; import com.ruoyi.common.security.feign.FeignAutoConfiguration; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited // 表示通过aop框架暴露该代理对象,AopContext能够访问 @EnableAspectJAutoProxy(exposeProxy = true) // 指定要扫描的Mapper类的包的路径 @MapperScan("com.ruoyi.**.mapper") // 开启线程异步执行 @EnableAsync // 自动加载类 @Import({ ApplicationConfig.class, FeignAutoConfiguration.class }) public @interface EnableCustomConfig { } package com.sgd.common.security.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.Import; import org.springframework.scheduling.annotation.EnableAsync; import com.sgd.common.security.config.ApplicationConfig; import com.sgd.common.security.feign.FeignAutoConfiguration; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited // 表示通过aop框架暴露该代理对象,AopContext能够访问 @EnableAspectJAutoProxy(exposeProxy = true) // 指定要扫描的Mapper类的包的路径 @MapperScan("com.sgd.**.mapper") // 开启线程异步执行 @EnableAsync // 自动加载类 @Import({ ApplicationConfig.class, FeignAutoConfiguration.class }) public @interface EnableCustomConfig { } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/annotation/EnableRyFeignClients.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableRyFeignClients.java @@ -1,29 +1,29 @@ package com.ruoyi.common.security.annotation; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.core.annotation.AliasFor; import java.lang.annotation.*; /** * 自定义feign注解 * 添加basePackages路径 * * @author ruoyi */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @EnableFeignClients public @interface EnableRyFeignClients { String[] value() default {}; @AliasFor(annotation = EnableFeignClients.class, attribute = "basePackages") String[] basePackages() default { "com.ruoyi" }; Class<?>[] basePackageClasses() default {}; Class<?>[] defaultConfiguration() default {}; Class<?>[] clients() default {}; } package com.sgd.common.security.annotation; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.core.annotation.AliasFor; import java.lang.annotation.*; /** * 自定义feign注解 * 添加basePackages路径 * * @author ruoyi */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @EnableFeignClients public @interface EnableRyFeignClients { String[] value() default {}; @AliasFor(annotation = EnableFeignClients.class, attribute = "basePackages") String[] basePackages() default { "com.sgd" }; Class<?>[] basePackageClasses() default {}; Class<?>[] defaultConfiguration() default {}; Class<?>[] clients() default {}; } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/annotation/InnerAuth.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/InnerAuth.java @@ -1,19 +1,19 @@ package com.ruoyi.common.security.annotation; import java.lang.annotation.*; /** * 内部认证注解 * * @author ruoyi */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface InnerAuth { /** * 是否校验用户信息 */ boolean isUser() default false; package com.sgd.common.security.annotation; import java.lang.annotation.*; /** * 内部认证注解 * * @author ruoyi */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface InnerAuth { /** * 是否校验用户信息 */ boolean isUser() default false; } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/annotation/Logical.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/Logical.java @@ -1,20 +1,20 @@ package com.ruoyi.common.security.annotation; /** * 权限注解的验证模式 * * @author ruoyi * */ public enum Logical { /** * 必须具有所有的元素 */ AND, /** * 只需具有其中一个元素 */ OR } package com.sgd.common.security.annotation; /** * 权限注解的验证模式 * * @author ruoyi * */ public enum Logical { /** * 必须具有所有的元素 */ AND, /** * 只需具有其中一个元素 */ OR } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/annotation/RequiresLogin.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresLogin.java @@ -1,18 +1,18 @@ package com.ruoyi.common.security.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 登录认证:只有登录之后才能进入该方法 * * @author ruoyi * */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) public @interface RequiresLogin { } package com.sgd.common.security.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 登录认证:只有登录之后才能进入该方法 * * @author ruoyi * */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) public @interface RequiresLogin { } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/annotation/RequiresPermissions.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresPermissions.java @@ -1,27 +1,27 @@ package com.ruoyi.common.security.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 权限认证:必须具有指定权限才能进入该方法 * * @author ruoyi * */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) public @interface RequiresPermissions { /** * 需要校验的权限码 */ String[] value() default {}; /** * 验证模式:AND | OR,默认AND */ Logical logical() default Logical.AND; } package com.sgd.common.security.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 权限认证:必须具有指定权限才能进入该方法 * * @author ruoyi * */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) public @interface RequiresPermissions { /** * 需要校验的权限码 */ String[] value() default {}; /** * 验证模式:AND | OR,默认AND */ Logical logical() default Logical.AND; } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/annotation/RequiresRoles.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresRoles.java @@ -1,26 +1,26 @@ package com.ruoyi.common.security.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 角色认证:必须具有指定角色标识才能进入该方法 * * @author ruoyi */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) public @interface RequiresRoles { /** * 需要校验的角色标识 */ String[] value() default {}; /** * 验证逻辑:AND | OR,默认AND */ Logical logical() default Logical.AND; } package com.sgd.common.security.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 角色认证:必须具有指定角色标识才能进入该方法 * * @author ruoyi */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) public @interface RequiresRoles { /** * 需要校验的角色标识 */ String[] value() default {}; /** * 验证逻辑:AND | OR,默认AND */ Logical logical() default Logical.AND; } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/aspect/InnerAuthAspect.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/aspect/InnerAuthAspect.java @@ -1,51 +1,51 @@ package com.ruoyi.common.security.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.exception.InnerAuthException; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.security.annotation.InnerAuth; /** * 内部服务调用验证处理 * * @author ruoyi */ @Aspect @Component public class InnerAuthAspect implements Ordered { @Around("@annotation(innerAuth)") public Object innerAround(ProceedingJoinPoint point, InnerAuth innerAuth) throws Throwable { String source = ServletUtils.getRequest().getHeader(SecurityConstants.FROM_SOURCE); // 内部请求验证 if (!StringUtils.equals(SecurityConstants.INNER, source)) { throw new InnerAuthException("没有内部访问权限,不允许访问"); } String userid = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID); String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME); // 用户信息验证 if (innerAuth.isUser() && (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))) { throw new InnerAuthException("没有设置用户信息,不允许访问 "); } return point.proceed(); } /** * 确保在权限认证aop执行前执行 */ @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE + 1; } } package com.sgd.common.security.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import com.sgd.common.core.constant.SecurityConstants; import com.sgd.common.core.exception.InnerAuthException; import com.sgd.common.core.utils.ServletUtils; import com.sgd.common.core.utils.StringUtils; import com.sgd.common.security.annotation.InnerAuth; /** * 内部服务调用验证处理 * * @author ruoyi */ @Aspect @Component public class InnerAuthAspect implements Ordered { @Around("@annotation(innerAuth)") public Object innerAround(ProceedingJoinPoint point, InnerAuth innerAuth) throws Throwable { String source = ServletUtils.getRequest().getHeader(SecurityConstants.FROM_SOURCE); // 内部请求验证 if (!StringUtils.equals(SecurityConstants.INNER, source)) { throw new InnerAuthException("没有内部访问权限,不允许访问"); } String userid = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID); String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME); // 用户信息验证 if (innerAuth.isUser() && (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))) { throw new InnerAuthException("没有设置用户信息,不允许访问 "); } return point.proceed(); } /** * 确保在权限认证aop执行前执行 */ @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE + 1; } } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/auth/AuthLogic.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthLogic.java @@ -1,373 +1,373 @@ package com.ruoyi.common.security.auth; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.springframework.util.PatternMatchUtils; import com.ruoyi.common.core.context.SecurityContextHolder; import com.ruoyi.common.core.exception.auth.NotLoginException; import com.ruoyi.common.core.exception.auth.NotPermissionException; import com.ruoyi.common.core.exception.auth.NotRoleException; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.security.annotation.Logical; import com.ruoyi.common.security.annotation.RequiresLogin; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.annotation.RequiresRoles; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.model.LoginUser; /** * Token 权限验证,逻辑实现类 * * @author ruoyi */ public class AuthLogic { /** 所有权限标识 */ private static final String ALL_PERMISSION = "*:*:*"; /** 管理员角色权限标识 */ private static final String SUPER_ADMIN = "admin"; public TokenService tokenService = SpringUtils.getBean(TokenService.class); /** * 会话注销 */ public void logout() { String token = SecurityUtils.getToken(); if (token == null) { return; } logoutByToken(token); } /** * 会话注销,根据指定Token */ public void logoutByToken(String token) { tokenService.delLoginUser(token); } /** * 检验用户是否已经登录,如未登录,则抛出异常 */ public void checkLogin() { getLoginUser(); } /** * 获取当前用户缓存信息, 如果未登录,则抛出异常 * * @return 用户缓存信息 */ public LoginUser getLoginUser() { String token = SecurityUtils.getToken(); if (token == null) { throw new NotLoginException("未提供token"); } LoginUser loginUser = SecurityUtils.getLoginUser(); if (loginUser == null) { throw new NotLoginException("无效的token"); } return loginUser; } /** * 获取当前用户缓存信息, 如果未登录,则抛出异常 * * @param token 前端传递的认证信息 * @return 用户缓存信息 */ public LoginUser getLoginUser(String token) { return tokenService.getLoginUser(token); } /** * 验证当前用户有效期, 如果相差不足120分钟,自动刷新缓存 * * @param loginUser 当前用户信息 */ public void verifyLoginUserExpire(LoginUser loginUser) { tokenService.verifyToken(loginUser); } /** * 验证用户是否具备某权限 * * @param permission 权限字符串 * @return 用户是否具备某权限 */ public boolean hasPermi(String permission) { return hasPermi(getPermiList(), permission); } /** * 验证用户是否具备某权限, 如果验证未通过,则抛出异常: NotPermissionException * * @param permission 权限字符串 * @return 用户是否具备某权限 */ public void checkPermi(String permission) { if (!hasPermi(getPermiList(), permission)) { throw new NotPermissionException(permission); } } /** * 根据注解(@RequiresPermissions)鉴权, 如果验证未通过,则抛出异常: NotPermissionException * * @param requiresPermissions 注解对象 */ public void checkPermi(RequiresPermissions requiresPermissions) { SecurityContextHolder.setPermission(StringUtils.join(requiresPermissions.value(), ",")); if (requiresPermissions.logical() == Logical.AND) { checkPermiAnd(requiresPermissions.value()); } else { checkPermiOr(requiresPermissions.value()); } } /** * 验证用户是否含有指定权限,必须全部拥有 * * @param permissions 权限列表 */ public void checkPermiAnd(String... permissions) { Set<String> permissionList = getPermiList(); for (String permission : permissions) { if (!hasPermi(permissionList, permission)) { throw new NotPermissionException(permission); } } } /** * 验证用户是否含有指定权限,只需包含其中一个 * * @param permissions 权限码数组 */ public void checkPermiOr(String... permissions) { Set<String> permissionList = getPermiList(); for (String permission : permissions) { if (hasPermi(permissionList, permission)) { return; } } if (permissions.length > 0) { throw new NotPermissionException(permissions); } } /** * 判断用户是否拥有某个角色 * * @param role 角色标识 * @return 用户是否具备某角色 */ public boolean hasRole(String role) { return hasRole(getRoleList(), role); } /** * 判断用户是否拥有某个角色, 如果验证未通过,则抛出异常: NotRoleException * * @param role 角色标识 */ public void checkRole(String role) { if (!hasRole(role)) { throw new NotRoleException(role); } } /** * 根据注解(@RequiresRoles)鉴权 * * @param requiresRoles 注解对象 */ public void checkRole(RequiresRoles requiresRoles) { if (requiresRoles.logical() == Logical.AND) { checkRoleAnd(requiresRoles.value()); } else { checkRoleOr(requiresRoles.value()); } } /** * 验证用户是否含有指定角色,必须全部拥有 * * @param roles 角色标识数组 */ public void checkRoleAnd(String... roles) { Set<String> roleList = getRoleList(); for (String role : roles) { if (!hasRole(roleList, role)) { throw new NotRoleException(role); } } } /** * 验证用户是否含有指定角色,只需包含其中一个 * * @param roles 角色标识数组 */ public void checkRoleOr(String... roles) { Set<String> roleList = getRoleList(); for (String role : roles) { if (hasRole(roleList, role)) { return; } } if (roles.length > 0) { throw new NotRoleException(roles); } } /** * 根据注解(@RequiresLogin)鉴权 * * @param at 注解对象 */ public void checkByAnnotation(RequiresLogin at) { this.checkLogin(); } /** * 根据注解(@RequiresRoles)鉴权 * * @param at 注解对象 */ public void checkByAnnotation(RequiresRoles at) { String[] roleArray = at.value(); if (at.logical() == Logical.AND) { this.checkRoleAnd(roleArray); } else { this.checkRoleOr(roleArray); } } /** * 根据注解(@RequiresPermissions)鉴权 * * @param at 注解对象 */ public void checkByAnnotation(RequiresPermissions at) { String[] permissionArray = at.value(); if (at.logical() == Logical.AND) { this.checkPermiAnd(permissionArray); } else { this.checkPermiOr(permissionArray); } } /** * 获取当前账号的角色列表 * * @return 角色列表 */ public Set<String> getRoleList() { try { LoginUser loginUser = getLoginUser(); return loginUser.getRoles(); } catch (Exception e) { return new HashSet<>(); } } /** * 获取当前账号的权限列表 * * @return 权限列表 */ public Set<String> getPermiList() { try { LoginUser loginUser = getLoginUser(); return loginUser.getPermissions(); } catch (Exception e) { return new HashSet<>(); } } /** * 判断是否包含权限 * * @param authorities 权限列表 * @param permission 权限字符串 * @return 用户是否具备某权限 */ public boolean hasPermi(Collection<String> authorities, String permission) { return authorities.stream().filter(StringUtils::hasText) .anyMatch(x -> ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission)); } /** * 判断是否包含角色 * * @param roles 角色列表 * @param role 角色 * @return 用户是否具备某角色权限 */ public boolean hasRole(Collection<String> roles, String role) { return roles.stream().filter(StringUtils::hasText) .anyMatch(x -> SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role)); } } package com.sgd.common.security.auth; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.springframework.util.PatternMatchUtils; import com.sgd.common.core.context.SecurityContextHolder; import com.sgd.common.core.exception.auth.NotLoginException; import com.sgd.common.core.exception.auth.NotPermissionException; import com.sgd.common.core.exception.auth.NotRoleException; import com.sgd.common.core.utils.SpringUtils; import com.sgd.common.core.utils.StringUtils; import com.sgd.common.security.annotation.Logical; import com.sgd.common.security.annotation.RequiresLogin; import com.sgd.common.security.annotation.RequiresPermissions; import com.sgd.common.security.annotation.RequiresRoles; import com.sgd.common.security.service.TokenService; import com.sgd.common.security.utils.SecurityUtils; import com.sgd.system.api.model.LoginUser; /** * Token 权限验证,逻辑实现类 * * @author ruoyi */ public class AuthLogic { /** 所有权限标识 */ private static final String ALL_PERMISSION = "*:*:*"; /** 管理员角色权限标识 */ private static final String SUPER_ADMIN = "admin"; public TokenService tokenService = SpringUtils.getBean(TokenService.class); /** * 会话注销 */ public void logout() { String token = SecurityUtils.getToken(); if (token == null) { return; } logoutByToken(token); } /** * 会话注销,根据指定Token */ public void logoutByToken(String token) { tokenService.delLoginUser(token); } /** * 检验用户是否已经登录,如未登录,则抛出异常 */ public void checkLogin() { getLoginUser(); } /** * 获取当前用户缓存信息, 如果未登录,则抛出异常 * * @return 用户缓存信息 */ public LoginUser getLoginUser() { String token = SecurityUtils.getToken(); if (token == null) { throw new NotLoginException("未提供token"); } LoginUser loginUser = SecurityUtils.getLoginUser(); if (loginUser == null) { throw new NotLoginException("无效的token"); } return loginUser; } /** * 获取当前用户缓存信息, 如果未登录,则抛出异常 * * @param token 前端传递的认证信息 * @return 用户缓存信息 */ public LoginUser getLoginUser(String token) { return tokenService.getLoginUser(token); } /** * 验证当前用户有效期, 如果相差不足120分钟,自动刷新缓存 * * @param loginUser 当前用户信息 */ public void verifyLoginUserExpire(LoginUser loginUser) { tokenService.verifyToken(loginUser); } /** * 验证用户是否具备某权限 * * @param permission 权限字符串 * @return 用户是否具备某权限 */ public boolean hasPermi(String permission) { return hasPermi(getPermiList(), permission); } /** * 验证用户是否具备某权限, 如果验证未通过,则抛出异常: NotPermissionException * * @param permission 权限字符串 * @return 用户是否具备某权限 */ public void checkPermi(String permission) { if (!hasPermi(getPermiList(), permission)) { throw new NotPermissionException(permission); } } /** * 根据注解(@RequiresPermissions)鉴权, 如果验证未通过,则抛出异常: NotPermissionException * * @param requiresPermissions 注解对象 */ public void checkPermi(RequiresPermissions requiresPermissions) { SecurityContextHolder.setPermission(StringUtils.join(requiresPermissions.value(), ",")); if (requiresPermissions.logical() == Logical.AND) { checkPermiAnd(requiresPermissions.value()); } else { checkPermiOr(requiresPermissions.value()); } } /** * 验证用户是否含有指定权限,必须全部拥有 * * @param permissions 权限列表 */ public void checkPermiAnd(String... permissions) { Set<String> permissionList = getPermiList(); for (String permission : permissions) { if (!hasPermi(permissionList, permission)) { throw new NotPermissionException(permission); } } } /** * 验证用户是否含有指定权限,只需包含其中一个 * * @param permissions 权限码数组 */ public void checkPermiOr(String... permissions) { Set<String> permissionList = getPermiList(); for (String permission : permissions) { if (hasPermi(permissionList, permission)) { return; } } if (permissions.length > 0) { throw new NotPermissionException(permissions); } } /** * 判断用户是否拥有某个角色 * * @param role 角色标识 * @return 用户是否具备某角色 */ public boolean hasRole(String role) { return hasRole(getRoleList(), role); } /** * 判断用户是否拥有某个角色, 如果验证未通过,则抛出异常: NotRoleException * * @param role 角色标识 */ public void checkRole(String role) { if (!hasRole(role)) { throw new NotRoleException(role); } } /** * 根据注解(@RequiresRoles)鉴权 * * @param requiresRoles 注解对象 */ public void checkRole(RequiresRoles requiresRoles) { if (requiresRoles.logical() == Logical.AND) { checkRoleAnd(requiresRoles.value()); } else { checkRoleOr(requiresRoles.value()); } } /** * 验证用户是否含有指定角色,必须全部拥有 * * @param roles 角色标识数组 */ public void checkRoleAnd(String... roles) { Set<String> roleList = getRoleList(); for (String role : roles) { if (!hasRole(roleList, role)) { throw new NotRoleException(role); } } } /** * 验证用户是否含有指定角色,只需包含其中一个 * * @param roles 角色标识数组 */ public void checkRoleOr(String... roles) { Set<String> roleList = getRoleList(); for (String role : roles) { if (hasRole(roleList, role)) { return; } } if (roles.length > 0) { throw new NotRoleException(roles); } } /** * 根据注解(@RequiresLogin)鉴权 * * @param at 注解对象 */ public void checkByAnnotation(RequiresLogin at) { this.checkLogin(); } /** * 根据注解(@RequiresRoles)鉴权 * * @param at 注解对象 */ public void checkByAnnotation(RequiresRoles at) { String[] roleArray = at.value(); if (at.logical() == Logical.AND) { this.checkRoleAnd(roleArray); } else { this.checkRoleOr(roleArray); } } /** * 根据注解(@RequiresPermissions)鉴权 * * @param at 注解对象 */ public void checkByAnnotation(RequiresPermissions at) { String[] permissionArray = at.value(); if (at.logical() == Logical.AND) { this.checkPermiAnd(permissionArray); } else { this.checkPermiOr(permissionArray); } } /** * 获取当前账号的角色列表 * * @return 角色列表 */ public Set<String> getRoleList() { try { LoginUser loginUser = getLoginUser(); return loginUser.getRoles(); } catch (Exception e) { return new HashSet<>(); } } /** * 获取当前账号的权限列表 * * @return 权限列表 */ public Set<String> getPermiList() { try { LoginUser loginUser = getLoginUser(); return loginUser.getPermissions(); } catch (Exception e) { return new HashSet<>(); } } /** * 判断是否包含权限 * * @param authorities 权限列表 * @param permission 权限字符串 * @return 用户是否具备某权限 */ public boolean hasPermi(Collection<String> authorities, String permission) { return authorities.stream().filter(StringUtils::hasText) .anyMatch(x -> ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission)); } /** * 判断是否包含角色 * * @param roles 角色列表 * @param role 角色 * @return 用户是否具备某角色权限 */ public boolean hasRole(Collection<String> roles, String role) { return roles.stream().filter(StringUtils::hasText) .anyMatch(x -> SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role)); } } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/auth/AuthUtil.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthUtil.java @@ -1,167 +1,167 @@ package com.ruoyi.common.security.auth; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.annotation.RequiresRoles; import com.ruoyi.system.api.model.LoginUser; /** * Token 权限验证工具类 * * @author ruoyi */ public class AuthUtil { /** * 底层的 AuthLogic 对象 */ public static AuthLogic authLogic = new AuthLogic(); /** * 会话注销 */ public static void logout() { authLogic.logout(); } /** * 会话注销,根据指定Token * * @param token 指定token */ public static void logoutByToken(String token) { authLogic.logoutByToken(token); } /** * 检验当前会话是否已经登录,如未登录,则抛出异常 */ public static void checkLogin() { authLogic.checkLogin(); } /** * 获取当前登录用户信息 * * @param token 指定token * @return 用户信息 */ public static LoginUser getLoginUser(String token) { return authLogic.getLoginUser(token); } /** * 验证当前用户有效期 * * @param loginUser 用户信息 */ public static void verifyLoginUserExpire(LoginUser loginUser) { authLogic.verifyLoginUserExpire(loginUser); } /** * 当前账号是否含有指定角色标识, 返回true或false * * @param role 角色标识 * @return 是否含有指定角色标识 */ public static boolean hasRole(String role) { return authLogic.hasRole(role); } /** * 当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException * * @param role 角色标识 */ public static void checkRole(String role) { authLogic.checkRole(role); } /** * 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotRoleException * * @param requiresRoles 角色权限注解 */ public static void checkRole(RequiresRoles requiresRoles) { authLogic.checkRole(requiresRoles); } /** * 当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] * * @param roles 角色标识数组 */ public static void checkRoleAnd(String... roles) { authLogic.checkRoleAnd(roles); } /** * 当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] * * @param roles 角色标识数组 */ public static void checkRoleOr(String... roles) { authLogic.checkRoleOr(roles); } /** * 当前账号是否含有指定权限, 返回true或false * * @param permission 权限码 * @return 是否含有指定权限 */ public static boolean hasPermi(String permission) { return authLogic.hasPermi(permission); } /** * 当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException * * @param permission 权限码 */ public static void checkPermi(String permission) { authLogic.checkPermi(permission); } /** * 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotPermissionException * * @param requiresPermissions 权限注解 */ public static void checkPermi(RequiresPermissions requiresPermissions) { authLogic.checkPermi(requiresPermissions); } /** * 当前账号是否含有指定权限 [指定多个,必须全部验证通过] * * @param permissions 权限码数组 */ public static void checkPermiAnd(String... permissions) { authLogic.checkPermiAnd(permissions); } /** * 当前账号是否含有指定权限 [指定多个,只要其一验证通过即可] * * @param permissions 权限码数组 */ public static void checkPermiOr(String... permissions) { authLogic.checkPermiOr(permissions); } } package com.sgd.common.security.auth; import com.sgd.common.security.annotation.RequiresPermissions; import com.sgd.common.security.annotation.RequiresRoles; import com.sgd.system.api.model.LoginUser; /** * Token 权限验证工具类 * * @author ruoyi */ public class AuthUtil { /** * 底层的 AuthLogic 对象 */ public static AuthLogic authLogic = new AuthLogic(); /** * 会话注销 */ public static void logout() { authLogic.logout(); } /** * 会话注销,根据指定Token * * @param token 指定token */ public static void logoutByToken(String token) { authLogic.logoutByToken(token); } /** * 检验当前会话是否已经登录,如未登录,则抛出异常 */ public static void checkLogin() { authLogic.checkLogin(); } /** * 获取当前登录用户信息 * * @param token 指定token * @return 用户信息 */ public static LoginUser getLoginUser(String token) { return authLogic.getLoginUser(token); } /** * 验证当前用户有效期 * * @param loginUser 用户信息 */ public static void verifyLoginUserExpire(LoginUser loginUser) { authLogic.verifyLoginUserExpire(loginUser); } /** * 当前账号是否含有指定角色标识, 返回true或false * * @param role 角色标识 * @return 是否含有指定角色标识 */ public static boolean hasRole(String role) { return authLogic.hasRole(role); } /** * 当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException * * @param role 角色标识 */ public static void checkRole(String role) { authLogic.checkRole(role); } /** * 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotRoleException * * @param requiresRoles 角色权限注解 */ public static void checkRole(RequiresRoles requiresRoles) { authLogic.checkRole(requiresRoles); } /** * 当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] * * @param roles 角色标识数组 */ public static void checkRoleAnd(String... roles) { authLogic.checkRoleAnd(roles); } /** * 当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] * * @param roles 角色标识数组 */ public static void checkRoleOr(String... roles) { authLogic.checkRoleOr(roles); } /** * 当前账号是否含有指定权限, 返回true或false * * @param permission 权限码 * @return 是否含有指定权限 */ public static boolean hasPermi(String permission) { return authLogic.hasPermi(permission); } /** * 当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException * * @param permission 权限码 */ public static void checkPermi(String permission) { authLogic.checkPermi(permission); } /** * 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotPermissionException * * @param requiresPermissions 权限注解 */ public static void checkPermi(RequiresPermissions requiresPermissions) { authLogic.checkPermi(requiresPermissions); } /** * 当前账号是否含有指定权限 [指定多个,必须全部验证通过] * * @param permissions 权限码数组 */ public static void checkPermiAnd(String... permissions) { authLogic.checkPermiAnd(permissions); } /** * 当前账号是否含有指定权限 [指定多个,只要其一验证通过即可] * * @param permissions 权限码数组 */ public static void checkPermiOr(String... permissions) { authLogic.checkPermiOr(permissions); } } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/config/ApplicationConfig.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/ApplicationConfig.java @@ -1,26 +1,26 @@ package com.ruoyi.common.security.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; import java.util.TimeZone; import org.springframework.context.annotation.Bean; /** * 系统配置 * * @author ruoyi */ public class ApplicationConfig { /** * 时区配置 */ @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = JsonMapper.builder().build(); objectMapper.findAndRegisterModules(); objectMapper.setTimeZone(TimeZone.getDefault()); return objectMapper; } } package com.sgd.common.security.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; import java.util.TimeZone; import org.springframework.context.annotation.Bean; /** * 系统配置 * * @author ruoyi */ public class ApplicationConfig { /** * 时区配置 */ @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = JsonMapper.builder().build(); objectMapper.findAndRegisterModules(); objectMapper.setTimeZone(TimeZone.getDefault()); return objectMapper; } } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/config/WebMvcConfig.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/WebMvcConfig.java @@ -1,33 +1,33 @@ package com.ruoyi.common.security.config; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.ruoyi.common.security.interceptor.HeaderInterceptor; /** * 拦截器配置 * * @author ruoyi */ public class WebMvcConfig implements WebMvcConfigurer { /** 不需要拦截地址 */ public static final String[] excludeUrls = { "/login", "/logout", "/refresh" }; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(getHeaderInterceptor()) .addPathPatterns("/**") .excludePathPatterns(excludeUrls) .order(-10); } /** * 自定义请求头拦截器 */ public HeaderInterceptor getHeaderInterceptor() { return new HeaderInterceptor(); } } package com.sgd.common.security.config; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.sgd.common.security.interceptor.HeaderInterceptor; /** * 拦截器配置 * * @author ruoyi */ public class WebMvcConfig implements WebMvcConfigurer { /** 不需要拦截地址 */ public static final String[] excludeUrls = { "/login", "/logout", "/refresh" }; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(getHeaderInterceptor()) .addPathPatterns("/**") .excludePathPatterns(excludeUrls) .order(-10); } /** * 自定义请求头拦截器 */ public HeaderInterceptor getHeaderInterceptor() { return new HeaderInterceptor(); } } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/feign/FeignAutoConfiguration.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignAutoConfiguration.java @@ -1,20 +1,20 @@ package com.ruoyi.common.security.feign; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import feign.RequestInterceptor; /** * Feign 配置注册 * * @author ruoyi **/ @Configuration public class FeignAutoConfiguration { @Bean public RequestInterceptor requestInterceptor() { return new FeignRequestInterceptor(); } } package com.sgd.common.security.feign; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import feign.RequestInterceptor; /** * Feign 配置注册 * * @author ruoyi **/ @Configuration public class FeignAutoConfiguration { @Bean public RequestInterceptor requestInterceptor() { return new FeignRequestInterceptor(); } } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/feign/FeignRequestInterceptor.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignRequestInterceptor.java @@ -1,54 +1,54 @@ package com.ruoyi.common.security.feign; import java.util.Map; import jakarta.servlet.http.HttpServletRequest; import org.springframework.stereotype.Component; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.ip.IpUtils; import feign.RequestInterceptor; import feign.RequestTemplate; /** * feign 请求拦截器 * * @author ruoyi */ @Component public class FeignRequestInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { HttpServletRequest httpServletRequest = ServletUtils.getRequest(); if (StringUtils.isNotNull(httpServletRequest)) { Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest); // 传递用户信息请求头,防止丢失 String userId = headers.get(SecurityConstants.DETAILS_USER_ID); if (StringUtils.isNotEmpty(userId)) { requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId); } String userKey = headers.get(SecurityConstants.USER_KEY); if (StringUtils.isNotEmpty(userKey)) { requestTemplate.header(SecurityConstants.USER_KEY, userKey); } String userName = headers.get(SecurityConstants.DETAILS_USERNAME); if (StringUtils.isNotEmpty(userName)) { requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName); } String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER); if (StringUtils.isNotEmpty(authentication)) { requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication); } // 配置客户端IP requestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr()); } } package com.sgd.common.security.feign; import java.util.Map; import jakarta.servlet.http.HttpServletRequest; import org.springframework.stereotype.Component; import com.sgd.common.core.constant.SecurityConstants; import com.sgd.common.core.utils.ServletUtils; import com.sgd.common.core.utils.StringUtils; import com.sgd.common.core.utils.ip.IpUtils; import feign.RequestInterceptor; import feign.RequestTemplate; /** * feign 请求拦截器 * * @author ruoyi */ @Component public class FeignRequestInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { HttpServletRequest httpServletRequest = ServletUtils.getRequest(); if (StringUtils.isNotNull(httpServletRequest)) { Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest); // 传递用户信息请求头,防止丢失 String userId = headers.get(SecurityConstants.DETAILS_USER_ID); if (StringUtils.isNotEmpty(userId)) { requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId); } String userKey = headers.get(SecurityConstants.USER_KEY); if (StringUtils.isNotEmpty(userKey)) { requestTemplate.header(SecurityConstants.USER_KEY, userKey); } String userName = headers.get(SecurityConstants.DETAILS_USERNAME); if (StringUtils.isNotEmpty(userName)) { requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName); } String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER); if (StringUtils.isNotEmpty(authentication)) { requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication); } // 配置客户端IP requestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr()); } } } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/handler/GlobalExceptionHandler.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/GlobalExceptionHandler.java @@ -1,166 +1,166 @@ package com.ruoyi.common.security.handler; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.validation.BindException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MissingPathVariableException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import com.ruoyi.common.core.constant.HttpStatus; import com.ruoyi.common.core.exception.DemoModeException; import com.ruoyi.common.core.exception.InnerAuthException; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.exception.auth.NotPermissionException; import com.ruoyi.common.core.exception.auth.NotRoleException; import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.html.EscapeUtil; import com.ruoyi.common.core.web.domain.AjaxResult; /** * 全局异常处理器 * * @author ruoyi */ @RestControllerAdvice public class GlobalExceptionHandler { private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 权限码异常 */ @ExceptionHandler(NotPermissionException.class) public AjaxResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage()); return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权"); } /** * 角色权限异常 */ @ExceptionHandler(NotRoleException.class) public AjaxResult handleNotRoleException(NotRoleException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage()); return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权"); } /** * 请求方式不支持 */ @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); return AjaxResult.error(e.getMessage()); } /** * 业务异常 */ @ExceptionHandler(ServiceException.class) public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) { log.error(e.getMessage(), e); Integer code = e.getCode(); return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage()); } /** * 请求路径中缺少必需的路径变量 */ @ExceptionHandler(MissingPathVariableException.class) public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e); return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName())); } /** * 请求参数类型不匹配 */ @ExceptionHandler(MethodArgumentTypeMismatchException.class) public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); String value = Convert.toStr(e.getValue()); if (StringUtils.isNotEmpty(value)) { value = EscapeUtil.clean(value); } log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e); return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), value)); } /** * 拦截未知的运行时异常 */ @ExceptionHandler(RuntimeException.class) public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',发生未知异常.", requestURI, e); return AjaxResult.error(e.getMessage()); } /** * 系统异常 */ @ExceptionHandler(Exception.class) public AjaxResult handleException(Exception e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',发生系统异常.", requestURI, e); return AjaxResult.error(e.getMessage()); } /** * 自定义验证异常 */ @ExceptionHandler(BindException.class) public AjaxResult handleBindException(BindException e) { log.error(e.getMessage(), e); String message = e.getAllErrors().get(0).getDefaultMessage(); return AjaxResult.error(message); } /** * 自定义验证异常 */ @ExceptionHandler(MethodArgumentNotValidException.class) public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { log.error(e.getMessage(), e); String message = e.getBindingResult().getFieldError().getDefaultMessage(); return AjaxResult.error(message); } /** * 内部认证异常 */ @ExceptionHandler(InnerAuthException.class) public AjaxResult handleInnerAuthException(InnerAuthException e) { return AjaxResult.error(e.getMessage()); } /** * 演示模式异常 */ @ExceptionHandler(DemoModeException.class) public AjaxResult handleDemoModeException(DemoModeException e) { return AjaxResult.error("演示模式,不允许操作"); } } package com.sgd.common.security.handler; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.validation.BindException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MissingPathVariableException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import com.sgd.common.core.constant.HttpStatus; import com.sgd.common.core.exception.DemoModeException; import com.sgd.common.core.exception.InnerAuthException; import com.sgd.common.core.exception.ServiceException; import com.sgd.common.core.exception.auth.NotPermissionException; import com.sgd.common.core.exception.auth.NotRoleException; import com.sgd.common.core.text.Convert; import com.sgd.common.core.utils.StringUtils; import com.sgd.common.core.utils.html.EscapeUtil; import com.sgd.common.core.web.domain.AjaxResult; /** * 全局异常处理器 * * @author ruoyi */ @RestControllerAdvice public class GlobalExceptionHandler { private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 权限码异常 */ @ExceptionHandler(NotPermissionException.class) public AjaxResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage()); return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权"); } /** * 角色权限异常 */ @ExceptionHandler(NotRoleException.class) public AjaxResult handleNotRoleException(NotRoleException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage()); return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权"); } /** * 请求方式不支持 */ @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); return AjaxResult.error(e.getMessage()); } /** * 业务异常 */ @ExceptionHandler(ServiceException.class) public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) { log.error(e.getMessage(), e); Integer code = e.getCode(); return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage()); } /** * 请求路径中缺少必需的路径变量 */ @ExceptionHandler(MissingPathVariableException.class) public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e); return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName())); } /** * 请求参数类型不匹配 */ @ExceptionHandler(MethodArgumentTypeMismatchException.class) public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); String value = Convert.toStr(e.getValue()); if (StringUtils.isNotEmpty(value)) { value = EscapeUtil.clean(value); } log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e); return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), value)); } /** * 拦截未知的运行时异常 */ @ExceptionHandler(RuntimeException.class) public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',发生未知异常.", requestURI, e); return AjaxResult.error(e.getMessage()); } /** * 系统异常 */ @ExceptionHandler(Exception.class) public AjaxResult handleException(Exception e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',发生系统异常.", requestURI, e); return AjaxResult.error(e.getMessage()); } /** * 自定义验证异常 */ @ExceptionHandler(BindException.class) public AjaxResult handleBindException(BindException e) { log.error(e.getMessage(), e); String message = e.getAllErrors().get(0).getDefaultMessage(); return AjaxResult.error(message); } /** * 自定义验证异常 */ @ExceptionHandler(MethodArgumentNotValidException.class) public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { log.error(e.getMessage(), e); String message = e.getBindingResult().getFieldError().getDefaultMessage(); return AjaxResult.error(message); } /** * 内部认证异常 */ @ExceptionHandler(InnerAuthException.class) public AjaxResult handleInnerAuthException(InnerAuthException e) { return AjaxResult.error(e.getMessage()); } /** * 演示模式异常 */ @ExceptionHandler(DemoModeException.class) public AjaxResult handleDemoModeException(DemoModeException e) { return AjaxResult.error("演示模式,不允许操作"); } } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/interceptor/HeaderInterceptor.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/interceptor/HeaderInterceptor.java @@ -1,54 +1,54 @@ package com.ruoyi.common.security.interceptor; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.AsyncHandlerInterceptor; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.context.SecurityContextHolder; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.security.auth.AuthUtil; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.model.LoginUser; /** * 自定义请求头拦截器,将Header数据封装到线程变量中方便获取 * 注意:此拦截器会同时验证当前用户有效期自动刷新有效期 * * @author ruoyi */ public class HeaderInterceptor implements AsyncHandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; } SecurityContextHolder.setUserId(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USER_ID)); SecurityContextHolder.setUserName(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USERNAME)); SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, SecurityConstants.USER_KEY)); String token = SecurityUtils.getToken(); if (StringUtils.isNotEmpty(token)) { LoginUser loginUser = AuthUtil.getLoginUser(token); if (StringUtils.isNotNull(loginUser)) { AuthUtil.verifyLoginUserExpire(loginUser); SecurityContextHolder.set(SecurityConstants.LOGIN_USER, loginUser); } } return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { SecurityContextHolder.remove(); } } package com.sgd.common.security.interceptor; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.AsyncHandlerInterceptor; import com.sgd.common.core.constant.SecurityConstants; import com.sgd.common.core.context.SecurityContextHolder; import com.sgd.common.core.utils.ServletUtils; import com.sgd.common.core.utils.StringUtils; import com.sgd.common.security.auth.AuthUtil; import com.sgd.common.security.utils.SecurityUtils; import com.sgd.system.api.model.LoginUser; /** * 自定义请求头拦截器,将Header数据封装到线程变量中方便获取 * 注意:此拦截器会同时验证当前用户有效期自动刷新有效期 * * @author ruoyi */ public class HeaderInterceptor implements AsyncHandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; } SecurityContextHolder.setUserId(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USER_ID)); SecurityContextHolder.setUserName(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USERNAME)); SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, SecurityConstants.USER_KEY)); String token = SecurityUtils.getToken(); if (StringUtils.isNotEmpty(token)) { LoginUser loginUser = AuthUtil.getLoginUser(token); if (StringUtils.isNotNull(loginUser)) { AuthUtil.verifyLoginUserExpire(loginUser); SecurityContextHolder.set(SecurityConstants.LOGIN_USER, loginUser); } } return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { SecurityContextHolder.remove(); } } sgd-common/sgd-common-security/src/main/java/com/sgd/common/security/utils/DictUtils.java
File was renamed from ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/DictUtils.java @@ -1,75 +1,75 @@ package com.ruoyi.common.security.utils; import java.util.Collection; import java.util.List; import com.alibaba.fastjson2.JSONArray; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.system.api.domain.SysDictData; /** * 字典工具类 * * @author ruoyi */ public class DictUtils { /** * 设置字典缓存 * * @param key 参数键 * @param dictDatas 字典数据列表 */ public static void setDictCache(String key, List<SysDictData> dictDatas) { SpringUtils.getBean(RedisService.class).setCacheObject(getCacheKey(key), dictDatas); } /** * 获取字典缓存 * * @param key 参数键 * @return dictDatas 字典数据列表 */ public static List<SysDictData> getDictCache(String key) { JSONArray arrayCache = SpringUtils.getBean(RedisService.class).getCacheObject(getCacheKey(key)); if (StringUtils.isNotNull(arrayCache)) { return arrayCache.toList(SysDictData.class); } return null; } /** * 删除指定字典缓存 * * @param key 字典键 */ public static void removeDictCache(String key) { SpringUtils.getBean(RedisService.class).deleteObject(getCacheKey(key)); } /** * 清空字典缓存 */ public static void clearDictCache() { Collection<String> keys = SpringUtils.getBean(RedisService.class).keys(CacheConstants.SYS_DICT_KEY + "*"); SpringUtils.getBean(RedisService.class).deleteObject(keys); } /** * 设置cache key * * @param configKey 参数键 * @return 缓存键key */ public static String getCacheKey(String configKey) { return CacheConstants.SYS_DICT_KEY + configKey; } } package com.sgd.common.security.utils; import java.util.Collection; import java.util.List; import com.alibaba.fastjson2.JSONArray; import com.sgd.common.core.constant.CacheConstants; import com.sgd.common.core.utils.SpringUtils; import com.sgd.common.core.utils.StringUtils; import com.sgd.common.redis.service.RedisService; import com.sgd.system.api.domain.SysDictData; /** * 字典工具类 * * @author ruoyi */ public class DictUtils { /** * 设置字典缓存 * * @param key 参数键 * @param dictDatas 字典数据列表 */ public static void setDictCache(String key, List<SysDictData> dictDatas) { SpringUtils.getBean(RedisService.class).setCacheObject(getCacheKey(key), dictDatas); } /** * 获取字典缓存 * * @param key 参数键 * @return dictDatas 字典数据列表 */ public static List<SysDictData> getDictCache(String key) { JSONArray arrayCache = SpringUtils.getBean(RedisService.class).getCacheObject(getCacheKey(key)); if (StringUtils.isNotNull(arrayCache)) { return arrayCache.toList(SysDictData.class); } return null; } /** * 删除指定字典缓存 * * @param key 字典键 */ public static void removeDictCache(String key) { SpringUtils.getBean(RedisService.class).deleteObject(getCacheKey(key)); } /** * 清空字典缓存 */ public static void clearDictCache() { Collection<String> keys = SpringUtils.getBean(RedisService.class).keys(CacheConstants.SYS_DICT_KEY + "*"); SpringUtils.getBean(RedisService.class).deleteObject(keys); } /** * 设置cache key * * @param configKey 参数键 * @return 缓存键key */ public static String getCacheKey(String configKey) { return CacheConstants.SYS_DICT_KEY + configKey; } }