diff --git a/db/0pigxx_boot.sql b/db/0pigxx_boot.sql index c28a3f24b..c2c76e08b 100644 --- a/db/0pigxx_boot.sql +++ b/db/0pigxx_boot.sql @@ -541,6 +541,7 @@ INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `p INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2103, '审计日志', NULL, '/admin/audit/index', NULL, 2001, 'iconfont icon-biaodan', '1', 1, '0', '0', '0', '', NULL, 'admin', '2023-03-02 12:28:47', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2104, '审计记录表删除', 'sys_audit_del', NULL, NULL, 2103, '1', '1', 3, '0', NULL, '1', '', NULL, 'admin', '2023-02-28 20:23:43', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2105, '导入导出', 'sys_audit_export', NULL, NULL, 2103, '1', '1', 3, '0', NULL, '1', '', NULL, 'admin', '2023-02-28 20:23:51', '0', 1); +INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2106, '敏感数据查看', 'no_mask', NULL, NULL, 2103, '1', '1', 3, '0', NULL, '1', '', NULL, 'admin', '2023-02-28 20:23:51', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2200, '字典管理', NULL, '/admin/dict/index', NULL, 2000, 'iconfont icon-zhongduancanshuchaxun', '1', 6, '0', NULL, '0', '', '2017-11-29 11:30:52', 'admin', '2023-02-16 15:24:29', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2201, '字典删除', 'sys_dict_del', NULL, NULL, 2200, NULL, '1', 1, '0', NULL, '1', ' ', '2017-11-29 11:30:11', ' ', '2021-05-25 03:12:55', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2202, '字典新增', 'sys_dict_add', NULL, NULL, 2200, NULL, '1', 1, '0', NULL, '1', ' ', '2018-05-11 22:34:55', ' ', '2021-05-25 03:12:55', '0', 1); diff --git a/db/2pigxx.sql b/db/2pigxx.sql index 665bd4d84..5bed1fb1c 100644 --- a/db/2pigxx.sql +++ b/db/2pigxx.sql @@ -538,6 +538,7 @@ INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `p INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2103, '审计日志', NULL, '/admin/audit/index', NULL, 2001, 'iconfont icon-biaodan', '1', 1, '0', '0', '0', '', NULL, 'admin', '2023-03-02 12:28:47', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2104, '审计记录表删除', 'sys_audit_del', NULL, NULL, 2103, '1', '1', 3, '0', NULL, '1', '', NULL, 'admin', '2023-02-28 20:23:43', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2105, '导入导出', 'sys_audit_export', NULL, NULL, 2103, '1', '1', 3, '0', NULL, '1', '', NULL, 'admin', '2023-02-28 20:23:51', '0', 1); +INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2106, '敏感数据查看', 'no_mask', NULL, NULL, 2103, '1', '1', 3, '0', NULL, '1', '', NULL, 'admin', '2023-02-28 20:23:51', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2200, '字典管理', NULL, '/admin/dict/index', NULL, 2000, 'iconfont icon-zhongduancanshuchaxun', '1', 6, '0', NULL, '0', '', '2017-11-29 11:30:52', 'admin', '2023-02-16 15:24:29', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2201, '字典删除', 'sys_dict_del', NULL, NULL, 2200, NULL, '1', 1, '0', NULL, '1', ' ', '2017-11-29 11:30:11', ' ', '2021-05-25 03:12:55', '0', 1); INSERT INTO `sys_menu` (`menu_id`, `name`, `permission`, `path`, `component`, `parent_id`, `icon`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `tenant_id`) VALUES (2202, '字典新增', 'sys_dict_add', NULL, NULL, 2200, NULL, '1', 1, '0', NULL, '1', ' ', '2018-05-11 22:34:55', ' ', '2021-05-25 03:12:55', '0', 1); diff --git a/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java b/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java index 76b017673..a18d55268 100644 --- a/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java +++ b/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java @@ -30,6 +30,7 @@ import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.security.component.PermitAllUrlProperties; import com.pig4cloud.pigx.common.security.component.PigxBearerTokenExtractor; import com.pig4cloud.pigx.common.security.component.ResourceAuthExceptionEntryPoint; +import com.pig4cloud.pigx.common.security.handler.SensitiveSkipHandler; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -45,6 +46,7 @@ import org.springframework.security.oauth2.server.authorization.config.annotatio import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; +import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter; import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationConverter; @@ -58,102 +60,104 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @RequiredArgsConstructor public class PigxBootSecurityServerConfiguration { - private final ResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint; + private final ResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint; - private final OpaqueTokenIntrospector customOpaqueTokenIntrospector; + private final OpaqueTokenIntrospector customOpaqueTokenIntrospector; - private final AuthenticationConverter accessTokenRequestConverter; + private final AuthenticationConverter accessTokenRequestConverter; - private final OAuth2AuthorizationService authorizationService; + private final OAuth2AuthorizationService authorizationService; - private final PigxBearerTokenExtractor pigBearerTokenExtractor; + private final PigxBearerTokenExtractor pigBearerTokenExtractor; - private final PasswordDecoderFilter passwordDecoderFilter; + private final PasswordDecoderFilter passwordDecoderFilter; - private final OAuth2TokenGenerator oAuth2TokenGenerator; + private final OAuth2TokenGenerator oAuth2TokenGenerator; - private final ValidateCodeFilter validateCodeFilter; + private final ValidateCodeFilter validateCodeFilter; - private final PermitAllUrlProperties permitAllUrl; + private final PermitAllUrlProperties permitAllUrl; - @Bean - @Order(Ordered.HIGHEST_PRECEDENCE) - public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, PigxAuthenticationSuccessEventHandler successEventHandler, - PigxAuthenticationFailureEventHandler failureEventHandler) throws Exception { - OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer(); + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, + PigxAuthenticationSuccessEventHandler successEventHandler, + PigxAuthenticationFailureEventHandler failureEventHandler) throws Exception { + OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer(); - // 增加验证码过滤器 - http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class); - // 增加密码解密过滤器 - http.addFilterBefore(passwordDecoderFilter, UsernamePasswordAuthenticationFilter.class); + // 增加验证码过滤器 + http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class); + // 增加密码解密过滤器 + http.addFilterBefore(passwordDecoderFilter, UsernamePasswordAuthenticationFilter.class); + http.addFilterAfter(new SensitiveSkipHandler(), BearerTokenAuthenticationFilter.class); - // 认证服务器配置 - http.with(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点 - tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter) // 注入自定义的授权认证Converter - .accessTokenResponseHandler(successEventHandler) // 登录成功处理器 - .errorResponseHandler(failureEventHandler);// 登录失败处理器 - }).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证 - oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常 - , Customizer.withDefaults()) - .with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 - .authorizationServerSettings( - AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), - Customizer.withDefaults()); + // 认证服务器配置 + http.with(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点 + tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter) // 注入自定义的授权认证Converter + .accessTokenResponseHandler(successEventHandler) // 登录成功处理器 + .errorResponseHandler(failureEventHandler);// 登录失败处理器 + }).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证 + oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常 + , Customizer.withDefaults()) + .with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 + .authorizationServerSettings( + AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), + Customizer.withDefaults()); - // 资源服务器配置 - AntPathRequestMatcher[] requestMatchers = permitAllUrl.getIgnoreUrls() - .stream() - .map(AntPathRequestMatcher::new) - .toList() - .toArray(new AntPathRequestMatcher[]{}); + // 资源服务器配置 + AntPathRequestMatcher[] requestMatchers = permitAllUrl.getIgnoreUrls() + .stream() + .map(AntPathRequestMatcher::new) + .toList() + .toArray(new AntPathRequestMatcher[] {}); - http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers) - .permitAll() - .anyRequest() - .authenticated()) - .oauth2ResourceServer( - oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector)) - .authenticationEntryPoint(resourceAuthExceptionEntryPoint) - .bearerTokenResolver(pigBearerTokenExtractor)) - .exceptionHandling(configurer -> configurer.authenticationEntryPoint(resourceAuthExceptionEntryPoint)) - .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) - .csrf(AbstractHttpConfigurer::disable); + http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers) + .permitAll() + .anyRequest() + .authenticated()) + .oauth2ResourceServer( + oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector)) + .authenticationEntryPoint(resourceAuthExceptionEntryPoint) + .bearerTokenResolver(pigBearerTokenExtractor)) + .exceptionHandling(configurer -> configurer.authenticationEntryPoint(resourceAuthExceptionEntryPoint)) + .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) + .csrf(AbstractHttpConfigurer::disable); - http.with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 - .authorizationServerSettings( - AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), - Customizer.withDefaults()); + http.with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 + .authorizationServerSettings( + AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), + Customizer.withDefaults()); - DefaultSecurityFilterChain securityFilterChain = http.build(); + DefaultSecurityFilterChain securityFilterChain = http.build(); - // 注入自定义授权模式实现 - addCustomOAuth2GrantAuthenticationProvider(http); - return securityFilterChain; - } + // 注入自定义授权模式实现 + addCustomOAuth2GrantAuthenticationProvider(http); + return securityFilterChain; + } - /** - * 注入授权模式实现提供方 - *
- * 1. 密码模式 - * 2. 短信登录 - */ - @SuppressWarnings("unchecked") - private void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http) { - AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); - OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class); + /** + * 注入授权模式实现提供方 + *
+ * 1. 密码模式
+ * 2. 短信登录
+ */
+ @SuppressWarnings("unchecked")
+ private void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http) {
+ AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
+ OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class);
- OAuth2ResourceOwnerPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider = new OAuth2ResourceOwnerPasswordAuthenticationProvider(
- authenticationManager, authorizationService, oAuth2TokenGenerator);
+ OAuth2ResourceOwnerPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider = new OAuth2ResourceOwnerPasswordAuthenticationProvider(
+ authenticationManager, authorizationService, oAuth2TokenGenerator);
- OAuth2ResourceOwnerSmsAuthenticationProvider resourceOwnerSmsAuthenticationProvider = new OAuth2ResourceOwnerSmsAuthenticationProvider(
- authenticationManager, authorizationService, oAuth2TokenGenerator);
+ OAuth2ResourceOwnerSmsAuthenticationProvider resourceOwnerSmsAuthenticationProvider = new OAuth2ResourceOwnerSmsAuthenticationProvider(
+ authenticationManager, authorizationService, oAuth2TokenGenerator);
- // 处理 UsernamePasswordAuthenticationToken
- http.authenticationProvider(new PigxDaoAuthenticationProvider());
- // 处理 OAuth2ResourceOwnerPasswordAuthenticationToken
- http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider);
- // 处理 OAuth2ResourceOwnerSmsAuthenticationToken
- http.authenticationProvider(resourceOwnerSmsAuthenticationProvider);
- }
+ // 处理 UsernamePasswordAuthenticationToken
+ http.authenticationProvider(new PigxDaoAuthenticationProvider());
+ // 处理 OAuth2ResourceOwnerPasswordAuthenticationToken
+ http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider);
+ // 处理 OAuth2ResourceOwnerSmsAuthenticationToken
+ http.authenticationProvider(resourceOwnerSmsAuthenticationProvider);
+ }
}
diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java
index 33e0c783b..b6c839ab1 100644
--- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java
+++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java
@@ -25,228 +25,233 @@ package com.pig4cloud.pigx.common.core.constant;
*/
public interface SecurityConstants {
- /**
- * 启动时是否检查Inner注解安全性
- */
- boolean INNER_CHECK = true;
+ /**
+ * 启动时是否检查Inner注解安全性
+ */
+ boolean INNER_CHECK = true;
- /**
- * 刷新
- */
- String REFRESH_TOKEN = "refresh_token";
+ /**
+ * 刷新
+ */
+ String REFRESH_TOKEN = "refresh_token";
- /**
- * 验证码有效期
- */
- int CODE_TIME = 60;
+ /**
+ * 验证码有效期
+ */
+ int CODE_TIME = 60;
- /**
- * 验证码长度
- */
- String CODE_SIZE = "4";
+ /**
+ * 验证码长度
+ */
+ String CODE_SIZE = "4";
- /**
- * 角色前缀
- */
- String ROLE = "ROLE_";
+ /**
+ * 角色前缀
+ */
+ String ROLE = "ROLE_";
- /**
- * 前缀
- */
- String PIGX_PREFIX = "pigx_";
+ /**
+ * 前缀
+ */
+ String PIGX_PREFIX = "pigx_";
- /**
- * token 相关前缀
- */
- String TOKEN_PREFIX = "token:";
+ /**
+ * token 相关前缀
+ */
+ String TOKEN_PREFIX = "token:";
- /**
- * oauth 相关前缀
- */
- String OAUTH_PREFIX = "oauth:";
+ /**
+ * oauth 相关前缀
+ */
+ String OAUTH_PREFIX = "oauth:";
- /**
- * 授权码模式code key 前缀
- */
- String OAUTH_CODE_PREFIX = "oauth:code:";
+ /**
+ * 授权码模式code key 前缀
+ */
+ String OAUTH_CODE_PREFIX = "oauth:code:";
- /**
- * 项目的license
- */
- String PIGX_LICENSE = "https://pig4cloud.com";
+ /**
+ * 项目的license
+ */
+ String PIGX_LICENSE = "https://pig4cloud.com";
- /**
- * 内部
- */
- String FROM_IN = "Y";
+ /**
+ * 内部
+ */
+ String FROM_IN = "Y";
- /**
- * 标志
- */
- String FROM = "from";
+ /**
+ * 标志
+ */
+ String FROM = "from";
- /**
- * 请求header
- */
- String HEADER_FROM_IN = FROM + "=" + FROM_IN;
+ /**
+ * 请求header
+ */
+ String HEADER_FROM_IN = FROM + "=" + FROM_IN;
- /**
- * OAUTH URL
- */
- String OAUTH_TOKEN_URL = "/oauth2/token";
+ /**
+ * OAUTH URL
+ */
+ String OAUTH_TOKEN_URL = "/oauth2/token";
- /**
- * 移动端授权
- */
- String GRANT_MOBILE = "mobile";
+ /**
+ * 移动端授权
+ */
+ String GRANT_MOBILE = "mobile";
- /**
- * TOC 客户端
- */
- String HEADER_TOC = "CLIENT-TOC";
+ /**
+ * TOC 客户端
+ */
+ String HEADER_TOC = "CLIENT-TOC";
- /**
- * TOC 客户端
- */
- String HEADER_TOC_YES = "Y";
+ /**
+ * TOC 客户端
+ */
+ String HEADER_TOC_YES = "Y";
- /**
- * QQ获取token
- */
- String QQ_AUTHORIZATION_CODE_URL = "https://graph.qq.com/oauth2.0/token?grant_type="
- + "authorization_code&code=%S&client_id=%s&redirect_uri=" + "%s&client_secret=%s";
+ /**
+ * QQ获取token
+ */
+ String QQ_AUTHORIZATION_CODE_URL = "https://graph.qq.com/oauth2.0/token?grant_type="
+ + "authorization_code&code=%S&client_id=%s&redirect_uri=" + "%s&client_secret=%s";
- /**
- * 微信获取OPENID
- */
- String WX_AUTHORIZATION_CODE_URL = "https://api.weixin.qq.com/sns/oauth2/access_token"
- + "?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
+ /**
+ * 微信获取OPENID
+ */
+ String WX_AUTHORIZATION_CODE_URL = "https://api.weixin.qq.com/sns/oauth2/access_token"
+ + "?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
- /**
- * 微信小程序OPENID
- */
- String MINI_APP_AUTHORIZATION_CODE_URL = "https://api.weixin.qq.com/sns/jscode2session"
- + "?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
+ /**
+ * 微信小程序OPENID
+ */
+ String MINI_APP_AUTHORIZATION_CODE_URL = "https://api.weixin.qq.com/sns/jscode2session"
+ + "?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
- /**
- * 码云获取token
- */
- String GITEE_AUTHORIZATION_CODE_URL = "https://gitee.com/oauth/token?grant_type="
- + "authorization_code&code=%S&client_id=%s&redirect_uri=" + "%s&client_secret=%s";
+ /**
+ * 码云获取token
+ */
+ String GITEE_AUTHORIZATION_CODE_URL = "https://gitee.com/oauth/token?grant_type="
+ + "authorization_code&code=%S&client_id=%s&redirect_uri=" + "%s&client_secret=%s";
- /**
- * 开源中国获取token
- */
- String OSC_AUTHORIZATION_CODE_URL = "https://www.oschina.net/action/openapi/token";
+ /**
+ * 开源中国获取token
+ */
+ String OSC_AUTHORIZATION_CODE_URL = "https://www.oschina.net/action/openapi/token";
- /**
- * QQ获取用户信息
- */
- String QQ_USER_INFO_URL = "https://graph.qq.com/oauth2.0/me?access_token=%s";
+ /**
+ * QQ获取用户信息
+ */
+ String QQ_USER_INFO_URL = "https://graph.qq.com/oauth2.0/me?access_token=%s";
- /**
- * 码云获取用户信息
- */
- String GITEE_USER_INFO_URL = "https://gitee.com/api/v5/user?access_token=%s";
+ /**
+ * 码云获取用户信息
+ */
+ String GITEE_USER_INFO_URL = "https://gitee.com/api/v5/user?access_token=%s";
- /**
- * 开源中国用户信息
- */
- String OSC_USER_INFO_URL = "https://www.oschina.net/action/openapi/user?access_token=%s&dataType=json";
+ /**
+ * 开源中国用户信息
+ */
+ String OSC_USER_INFO_URL = "https://www.oschina.net/action/openapi/user?access_token=%s&dataType=json";
- /**
- * 钉钉获取 token
- */
- String DING_OLD_GET_TOKEN = "https://oapi.dingtalk.com/gettoken";
+ /**
+ * 钉钉获取 token
+ */
+ String DING_OLD_GET_TOKEN = "https://oapi.dingtalk.com/gettoken";
- /**
- * 钉钉同步部门列表
- */
- String DING_OLD_DEPT_URL = "https://oapi.dingtalk.com/topapi/v2/department/listsub";
+ /**
+ * 钉钉同步部门列表
+ */
+ String DING_OLD_DEPT_URL = "https://oapi.dingtalk.com/topapi/v2/department/listsub";
- /**
- * 钉钉部门用户id列表
- */
- String DING_DEPT_USERIDS_URL = "https://oapi.dingtalk.com/topapi/user/listid";
+ /**
+ * 钉钉部门用户id列表
+ */
+ String DING_DEPT_USERIDS_URL = "https://oapi.dingtalk.com/topapi/user/listid";
- /**
- * 钉钉用户详情
- */
- String DING_USER_INFO_URL = "https://oapi.dingtalk.com/topapi/v2/user/get";
+ /**
+ * 钉钉用户详情
+ */
+ String DING_USER_INFO_URL = "https://oapi.dingtalk.com/topapi/v2/user/get";
- /**
- * {bcrypt} 加密的特征码
- */
- String BCRYPT = "{bcrypt}";
+ /**
+ * {bcrypt} 加密的特征码
+ */
+ String BCRYPT = "{bcrypt}";
- /**
- * 客户端模式
- */
- String CLIENT_CREDENTIALS = "client_credentials";
+ /**
+ * 客户端模式
+ */
+ String CLIENT_CREDENTIALS = "client_credentials";
- /**
- * 客户端编号
- */
- String CLIENT_ID = "client_id";
+ /**
+ * 客户端编号
+ */
+ String CLIENT_ID = "client_id";
- /**
- * 客户端唯一令牌
- */
- String CLIENT_RECREATE = "recreate_flag";
+ /**
+ * 客户端唯一令牌
+ */
+ String CLIENT_RECREATE = "recreate_flag";
- /**
- * 用户ID字段
- */
- String DETAILS_USER_ID = "user_id";
+ /**
+ * 用户ID字段
+ */
+ String DETAILS_USER_ID = "user_id";
- /**
- * 用户名
- */
- String DETAILS_USERNAME = "username";
+ /**
+ * 用户名
+ */
+ String DETAILS_USERNAME = "username";
- /**
- * 姓名
- */
- String NAME = "name";
+ /**
+ * 姓名
+ */
+ String NAME = "name";
- /**
- * 协议字段
- */
- String DETAILS_LICENSE = "license";
+ /**
+ * 协议字段
+ */
+ String DETAILS_LICENSE = "license";
- /**
- * 激活字段 兼容外围系统接入
- */
- String ACTIVE = "active";
+ /**
+ * 激活字段 兼容外围系统接入
+ */
+ String ACTIVE = "active";
- /**
- * AES 加密
- */
- String AES = "aes";
+ /**
+ * AES 加密
+ */
+ String AES = "aes";
- /**
- * 授权码模式confirm
- */
- String CUSTOM_CONSENT_PAGE_URI = "/token/confirm_access";
+ /**
+ * 授权码模式confirm
+ */
+ String CUSTOM_CONSENT_PAGE_URI = "/token/confirm_access";
- /**
- * {noop} 加密的特征码
- */
- String NOOP = "{noop}";
+ /**
+ * {noop} 加密的特征码
+ */
+ String NOOP = "{noop}";
- /**
- * 短信登录 参数名称
- */
- String SMS_PARAMETER_NAME = "mobile";
+ /**
+ * 短信登录 参数名称
+ */
+ String SMS_PARAMETER_NAME = "mobile";
- /**
- * 手机号登录
- */
- String APP = "mobile";
+ /**
+ * 手机号登录
+ */
+ String APP = "mobile";
- /**
- * 用户信息
- */
- String DETAILS_USER = "user_info";
+ /**
+ * 用户信息
+ */
+ String DETAILS_USER = "user_info";
+
+ /**
+ * 不脱敏的权限
+ */
+ String NO_MASK = "no_mask";
}
diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java
index f45b8b94b..a0e833b4a 100644
--- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java
+++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java
@@ -41,77 +41,84 @@ import java.util.Objects;
@AllArgsConstructor
public class SensitiveSerialize extends JsonSerializer
* 资源服务器认证授权配置
*/
@Slf4j
@@ -42,35 +44,38 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@RequiredArgsConstructor
public class PigxResourceServerConfiguration {
- protected final ResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint;
+ protected final ResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint;
- private final PermitAllUrlProperties permitAllUrl;
+ private final PermitAllUrlProperties permitAllUrl;
- private final PigxBearerTokenExtractor pigxBearerTokenExtractor;
+ private final PigxBearerTokenExtractor pigxBearerTokenExtractor;
- private final OpaqueTokenIntrospector customOpaqueTokenIntrospector;
+ private final OpaqueTokenIntrospector customOpaqueTokenIntrospector;
- @Bean
- @Order(Ordered.HIGHEST_PRECEDENCE)
- SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- AntPathRequestMatcher[] requestMatchers = permitAllUrl.getIgnoreUrls()
- .stream()
- .map(AntPathRequestMatcher::new)
- .toList()
- .toArray(new AntPathRequestMatcher[] {});
+ @Bean
+ @Order(Ordered.HIGHEST_PRECEDENCE)
+ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ AntPathRequestMatcher[] requestMatchers = permitAllUrl.getIgnoreUrls()
+ .stream()
+ .map(AntPathRequestMatcher::new)
+ .toList()
+ .toArray(new AntPathRequestMatcher[]{});
- http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers)
- .permitAll()
- .anyRequest()
- .authenticated())
- .oauth2ResourceServer(
- oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector))
- .authenticationEntryPoint(resourceAuthExceptionEntryPoint)
- .bearerTokenResolver(pigxBearerTokenExtractor))
- .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
- .csrf(AbstractHttpConfigurer::disable);
+ // 增加输出脱敏的处理
+ http.addFilterAfter(new SensitiveSkipHandler(), BearerTokenAuthenticationFilter.class);
- return http.build();
- }
+ http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers)
+ .permitAll()
+ .anyRequest()
+ .authenticated())
+ .oauth2ResourceServer(
+ oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector))
+ .authenticationEntryPoint(resourceAuthExceptionEntryPoint)
+ .bearerTokenResolver(pigxBearerTokenExtractor))
+ .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
+ .csrf(AbstractHttpConfigurer::disable);
+
+ return http.build();
+ }
}
diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/handler/SensitiveSkipHandler.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/handler/SensitiveSkipHandler.java
new file mode 100644
index 000000000..bacdd9eb7
--- /dev/null
+++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/handler/SensitiveSkipHandler.java
@@ -0,0 +1,42 @@
+package com.pig4cloud.pigx.common.security.handler;
+
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import com.pig4cloud.pigx.common.core.sensitive.SensitiveSkipContextHolder;
+import com.pig4cloud.pigx.common.security.service.PigxUser;
+import com.pig4cloud.pigx.common.security.util.SecurityUtils;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+/**
+ * 敏感词跳过的处理器
+ *
+ * @author lengleng
+ * @date 2024/6/26
+ */
+public class SensitiveSkipHandler extends OncePerRequestFilter {
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+ PigxUser user = SecurityUtils.getUser();
+
+ if (user == null) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ try {
+ if (user.getAuthorities().stream().map(GrantedAuthority::getAuthority)
+ .toList().contains(SecurityConstants.NO_MASK)) {
+ SensitiveSkipContextHolder.setSkip(true);
+ }
+ filterChain.doFilter(request, response);
+ } finally {
+ SensitiveSkipContextHolder.clear();
+ }
+ }
+}
diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java
index d9312784a..205d6c570 100644
--- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java
+++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java
@@ -38,63 +38,69 @@ import java.util.List;
@UtilityClass
public class SecurityUtils {
- /**
- * 获取Authentication
- */
- public Authentication getAuthentication() {
- return SecurityContextHolder.getContext().getAuthentication();
- }
+ /**
+ * 获取Authentication
+ */
+ public Authentication getAuthentication() {
+ return SecurityContextHolder.getContext().getAuthentication();
+ }
- /**
- * 获取Authentication Token
- * @return
- */
- public String getToken(){
- Authentication authentication = SecurityUtils.getAuthentication();
- if (authentication instanceof BearerTokenAuthentication bearerTokenAuthentication) {
- return bearerTokenAuthentication.getToken().getTokenValue();
- }
- return null;
- }
+ /**
+ * 获取Authentication Token
+ *
+ * @return
+ */
+ public String getToken() {
+ Authentication authentication = SecurityUtils.getAuthentication();
+ if (authentication instanceof BearerTokenAuthentication bearerTokenAuthentication) {
+ return bearerTokenAuthentication.getToken().getTokenValue();
+ }
+ return null;
+ }
- /**
- * 获取用户
- * @param authentication
- * @return PigxUser
- *
- */
- public PigxUser getUser(Authentication authentication) {
- Object principal = authentication.getPrincipal();
- if (principal instanceof PigxUser) {
- return (PigxUser) principal;
- }
- return null;
- }
+ /**
+ * 获取用户
+ *
+ * @param authentication
+ * @return PigxUser
+ *
+ */
+ public PigxUser getUser(Authentication authentication) {
+ if (authentication == null) {
+ return null;
+ }
+ Object principal = authentication.getPrincipal();
+ if (principal instanceof PigxUser) {
+ return (PigxUser) principal;
+ }
+ return null;
+ }
- /**
- * 获取用户
- */
- public PigxUser getUser() {
- Authentication authentication = getAuthentication();
- return getUser(authentication);
- }
+ /**
+ * 获取用户
+ */
+ public PigxUser getUser() {
+ Authentication authentication = getAuthentication();
+ return getUser(authentication);
+ }
- /**
- * 获取用户角色信息
- * @return 角色集合
- */
- public List