Commit 6a61db85082d36ffd5d3a26cc0937de11a5b41c1
1 parent
41c324ac
security: query string 支持传递 token 参数,解决 ws token 认证
Showing
6 changed files
with
34 additions
and
15 deletions
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 { | @@ -19,6 +19,13 @@ public class SecurityProperties { | ||
| 19 | */ | 19 | */ |
| 20 | @NotEmpty(message = "Token Header 不能为空") | 20 | @NotEmpty(message = "Token Header 不能为空") |
| 21 | private String tokenHeader = "Authorization"; | 21 | private String tokenHeader = "Authorization"; |
| 22 | + /** | ||
| 23 | + * HTTP 请求时,访问令牌的请求参数 | ||
| 24 | + * | ||
| 25 | + * 初始目的:解决 WebSocket 无法通过 header 传参,只能通过 token 参数拼接 | ||
| 26 | + */ | ||
| 27 | + @NotEmpty(message = "Token Parameter 不能为空") | ||
| 28 | + private String tokenParameter = "token"; | ||
| 22 | 29 | ||
| 23 | /** | 30 | /** |
| 24 | * mock 模式的开关 | 31 | * mock 模式的开关 |
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 { | @@ -129,8 +129,6 @@ public class YudaoWebSecurityConfigurerAdapter { | ||
| 129 | .antMatchers(buildAppApi("/**")).permitAll() | 129 | .antMatchers(buildAppApi("/**")).permitAll() |
| 130 | // 1.5 验证码captcha 允许匿名访问 | 130 | // 1.5 验证码captcha 允许匿名访问 |
| 131 | .antMatchers("/captcha/get", "/captcha/check").permitAll() | 131 | .antMatchers("/captcha/get", "/captcha/check").permitAll() |
| 132 | - // 1.6 webSocket 允许匿名访问 | ||
| 133 | - .antMatchers("/websocket/message").permitAll() | ||
| 134 | // ②:每个项目的自定义规则 | 132 | // ②:每个项目的自定义规则 |
| 135 | .and().authorizeRequests(registry -> // 下面,循环设置自定义规则 | 133 | .and().authorizeRequests(registry -> // 下面,循环设置自定义规则 |
| 136 | authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry))) | 134 | authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry))) |
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 { | @@ -41,7 +41,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { | ||
| 41 | @SuppressWarnings("NullableProblems") | 41 | @SuppressWarnings("NullableProblems") |
| 42 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) | 42 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) |
| 43 | throws ServletException, IOException { | 43 | throws ServletException, IOException { |
| 44 | - String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader()); | 44 | + String token = SecurityFrameworkUtils.obtainAuthorization(request, |
| 45 | + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); | ||
| 45 | if (StrUtil.isNotEmpty(token)) { | 46 | if (StrUtil.isNotEmpty(token)) { |
| 46 | Integer userType = WebFrameworkUtils.getLoginUserType(request); | 47 | Integer userType = WebFrameworkUtils.getLoginUserType(request); |
| 47 | try { | 48 | try { |
| @@ -74,7 +75,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { | @@ -74,7 +75,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { | ||
| 74 | return null; | 75 | return null; |
| 75 | } | 76 | } |
| 76 | // 用户类型不匹配,无权限 | 77 | // 用户类型不匹配,无权限 |
| 77 | - if (ObjectUtil.notEqual(accessToken.getUserType(), userType)) { | 78 | + // 注意:只有 /admin-api/* 和 /app-api/* 有 userType,才需要比对用户类型 |
| 79 | + // TODO 芋艿:ws 要不要区分开? | ||
| 80 | + if (userType != null | ||
| 81 | + && ObjectUtil.notEqual(accessToken.getUserType(), userType)) { | ||
| 78 | throw new AccessDeniedException("错误的用户类型"); | 82 | throw new AccessDeniedException("错误的用户类型"); |
| 79 | } | 83 | } |
| 80 | // 构建登录用户 | 84 | // 构建登录用户 |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
| 1 | package cn.iocoder.yudao.framework.security.core.util; | 1 | package cn.iocoder.yudao.framework.security.core.util; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 3 | import cn.iocoder.yudao.framework.security.core.LoginUser; | 4 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| 4 | import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; | 5 | import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; |
| 5 | import org.springframework.lang.Nullable; | 6 | import org.springframework.lang.Nullable; |
| @@ -20,6 +21,9 @@ import java.util.Collections; | @@ -20,6 +21,9 @@ import java.util.Collections; | ||
| 20 | */ | 21 | */ |
| 21 | public class SecurityFrameworkUtils { | 22 | public class SecurityFrameworkUtils { |
| 22 | 23 | ||
| 24 | + /** | ||
| 25 | + * HEADER 认证头 value 的前缀 | ||
| 26 | + */ | ||
| 23 | public static final String AUTHORIZATION_BEARER = "Bearer"; | 27 | public static final String AUTHORIZATION_BEARER = "Bearer"; |
| 24 | 28 | ||
| 25 | private SecurityFrameworkUtils() {} | 29 | private SecurityFrameworkUtils() {} |
| @@ -28,19 +32,23 @@ public class SecurityFrameworkUtils { | @@ -28,19 +32,23 @@ public class SecurityFrameworkUtils { | ||
| 28 | * 从请求中,获得认证 Token | 32 | * 从请求中,获得认证 Token |
| 29 | * | 33 | * |
| 30 | * @param request 请求 | 34 | * @param request 请求 |
| 31 | - * @param header 认证 Token 对应的 Header 名字 | 35 | + * @param headerName 认证 Token 对应的 Header 名字 |
| 36 | + * @param parameterName 认证 Token 对应的 Parameter 名字 | ||
| 32 | * @return 认证 Token | 37 | * @return 认证 Token |
| 33 | */ | 38 | */ |
| 34 | - public static String obtainAuthorization(HttpServletRequest request, String header) { | ||
| 35 | - String authorization = request.getHeader(header); | ||
| 36 | - if (!StringUtils.hasText(authorization)) { | ||
| 37 | - return null; | 39 | + public static String obtainAuthorization(HttpServletRequest request, |
| 40 | + String headerName, String parameterName) { | ||
| 41 | + // 1. 获得 Token。优先级:Header > Parameter | ||
| 42 | + String token = request.getHeader(headerName); | ||
| 43 | + if (StrUtil.isEmpty(token)) { | ||
| 44 | + token = request.getParameter(parameterName); | ||
| 38 | } | 45 | } |
| 39 | - int index = authorization.indexOf(AUTHORIZATION_BEARER + " "); | ||
| 40 | - if (index == -1) { // 未找到 | 46 | + if (!StringUtils.hasText(token)) { |
| 41 | return null; | 47 | return null; |
| 42 | } | 48 | } |
| 43 | - return authorization.substring(index + 7).trim(); | 49 | + // 2. 去除 Token 中带的 Bearer |
| 50 | + int index = token.indexOf(AUTHORIZATION_BEARER + " "); | ||
| 51 | + return index >= 0 ? token.substring(index + 7).trim() : token; | ||
| 44 | } | 52 | } |
| 45 | 53 | ||
| 46 | /** | 54 | /** |
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 { | @@ -53,7 +53,8 @@ public class AppAuthController { | ||
| 53 | @PermitAll | 53 | @PermitAll |
| 54 | @Operation(summary = "登出系统") | 54 | @Operation(summary = "登出系统") |
| 55 | public CommonResult<Boolean> logout(HttpServletRequest request) { | 55 | public CommonResult<Boolean> logout(HttpServletRequest request) { |
| 56 | - String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader()); | 56 | + String token = SecurityFrameworkUtils.obtainAuthorization(request, |
| 57 | + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); | ||
| 57 | if (StrUtil.isNotBlank(token)) { | 58 | if (StrUtil.isNotBlank(token)) { |
| 58 | authService.logout(token); | 59 | authService.logout(token); |
| 59 | } | 60 | } |
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; | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 7 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 8 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 8 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 9 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; | 9 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; |
| 10 | +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | ||
| 10 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; | 11 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; |
| 11 | import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; | 12 | import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; |
| 12 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; | 13 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; |
| @@ -38,7 +39,6 @@ import java.util.Set; | @@ -38,7 +39,6 @@ import java.util.Set; | ||
| 38 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 39 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 39 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 40 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 40 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 41 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 41 | -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization; | ||
| 42 | 42 | ||
| 43 | @Tag(name = "管理后台 - 认证") | 43 | @Tag(name = "管理后台 - 认证") |
| 44 | @RestController | 44 | @RestController |
| @@ -76,7 +76,8 @@ public class AuthController { | @@ -76,7 +76,8 @@ public class AuthController { | ||
| 76 | @Operation(summary = "登出系统") | 76 | @Operation(summary = "登出系统") |
| 77 | @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | 77 | @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 |
| 78 | public CommonResult<Boolean> logout(HttpServletRequest request) { | 78 | public CommonResult<Boolean> logout(HttpServletRequest request) { |
| 79 | - String token = obtainAuthorization(request, securityProperties.getTokenHeader()); | 79 | + String token = SecurityFrameworkUtils.obtainAuthorization(request, |
| 80 | + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); | ||
| 80 | if (StrUtil.isNotBlank(token)) { | 81 | if (StrUtil.isNotBlank(token)) { |
| 81 | authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); | 82 | authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); |
| 82 | } | 83 | } |