From 6a61db85082d36ffd5d3a26cc0937de11a5b41c1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 22 Nov 2023 23:02:59 +0800 Subject: [PATCH] =?UTF-8?q?security:=20query=20string=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BC=A0=E9=80=92=20token=20=E5=8F=82=E6=95=B0=EF=BC=8C?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=20ws=20token=20=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/config/SecurityProperties.java | 7 +++++ .../YudaoWebSecurityConfigurerAdapter.java | 2 -- .../filter/TokenAuthenticationFilter.java | 8 ++++-- .../core/util/SecurityFrameworkUtils.java | 26 ++++++++++++------- .../app/auth/AppAuthController.java | 3 ++- .../controller/admin/auth/AuthController.java | 5 ++-- 6 files changed, 35 insertions(+), 16 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java index d95dd5ff5..3d19f32a6 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java @@ -19,6 +19,13 @@ public class SecurityProperties { */ @NotEmpty(message = "Token Header 不能为空") private String tokenHeader = "Authorization"; + /** + * HTTP 请求时,访问令牌的请求参数 + * + * 初始目的:解决 WebSocket 无法通过 header 传参,只能通过 token 参数拼接 + */ + @NotEmpty(message = "Token Parameter 不能为空") + private String tokenParameter = "token"; /** * mock 模式的开关 diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java index 78aa328ad..06a8f9be2 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java @@ -129,8 +129,6 @@ public class YudaoWebSecurityConfigurerAdapter { .antMatchers(buildAppApi("/**")).permitAll() // 1.5 验证码captcha 允许匿名访问 .antMatchers("/captcha/get", "/captcha/check").permitAll() - // 1.6 webSocket 允许匿名访问 - .antMatchers("/websocket/message").permitAll() // ②:每个项目的自定义规则 .and().authorizeRequests(registry -> // 下面,循环设置自定义规则 authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry))) diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java index e87f5bc44..601415c00 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/TokenAuthenticationFilter.java @@ -41,7 +41,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { @SuppressWarnings("NullableProblems") protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { - String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader()); + String token = SecurityFrameworkUtils.obtainAuthorization(request, + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); if (StrUtil.isNotEmpty(token)) { Integer userType = WebFrameworkUtils.getLoginUserType(request); try { @@ -74,7 +75,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { return null; } // 用户类型不匹配,无权限 - if (ObjectUtil.notEqual(accessToken.getUserType(), userType)) { + // 注意:只有 /admin-api/* 和 /app-api/* 有 userType,才需要比对用户类型 + // TODO 芋艿:ws 要不要区分开? + if (userType != null + && ObjectUtil.notEqual(accessToken.getUserType(), userType)) { throw new AccessDeniedException("错误的用户类型"); } // 构建登录用户 diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java index 5dc17b626..3caa7f98b 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.security.core.util; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import org.springframework.lang.Nullable; @@ -20,6 +21,9 @@ import java.util.Collections; */ public class SecurityFrameworkUtils { + /** + * HEADER 认证头 value 的前缀 + */ public static final String AUTHORIZATION_BEARER = "Bearer"; private SecurityFrameworkUtils() {} @@ -28,19 +32,23 @@ public class SecurityFrameworkUtils { * 从请求中,获得认证 Token * * @param request 请求 - * @param header 认证 Token 对应的 Header 名字 + * @param headerName 认证 Token 对应的 Header 名字 + * @param parameterName 认证 Token 对应的 Parameter 名字 * @return 认证 Token */ - public static String obtainAuthorization(HttpServletRequest request, String header) { - String authorization = request.getHeader(header); - if (!StringUtils.hasText(authorization)) { + public static String obtainAuthorization(HttpServletRequest request, + String headerName, String parameterName) { + // 1. 获得 Token。优先级:Header > Parameter + String token = request.getHeader(headerName); + if (StrUtil.isEmpty(token)) { + token = request.getParameter(parameterName); + } + if (!StringUtils.hasText(token)) { return null; } - int index = authorization.indexOf(AUTHORIZATION_BEARER + " "); - if (index == -1) { // 未找到 - return null; - } - return authorization.substring(index + 7).trim(); + // 2. 去除 Token 中带的 Bearer + int index = token.indexOf(AUTHORIZATION_BEARER + " "); + return index >= 0 ? token.substring(index + 7).trim() : token; } /** diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java index ed3963e90..4b6ed7b26 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java @@ -53,7 +53,8 @@ public class AppAuthController { @PermitAll @Operation(summary = "登出系统") public CommonResult logout(HttpServletRequest request) { - String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader()); + String token = SecurityFrameworkUtils.obtainAuthorization(request, + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); if (StrUtil.isNotBlank(token)) { authService.logout(token); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java index c2eae8d38..061539494 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.framework.security.config.SecurityProperties; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; @@ -38,7 +39,6 @@ import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization; @Tag(name = "管理后台 - 认证") @RestController @@ -76,7 +76,8 @@ public class AuthController { @Operation(summary = "登出系统") @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 public CommonResult logout(HttpServletRequest request) { - String token = obtainAuthorization(request, securityProperties.getTokenHeader()); + String token = SecurityFrameworkUtils.obtainAuthorization(request, + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); if (StrUtil.isNotBlank(token)) { authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); }