security: query string 支持传递 token 参数,解决 ws token 认证
This commit is contained in:
parent
41c324acc3
commit
6a61db8508
|
@ -19,6 +19,13 @@ public class SecurityProperties {
|
||||||
*/
|
*/
|
||||||
@NotEmpty(message = "Token Header 不能为空")
|
@NotEmpty(message = "Token Header 不能为空")
|
||||||
private String tokenHeader = "Authorization";
|
private String tokenHeader = "Authorization";
|
||||||
|
/**
|
||||||
|
* HTTP 请求时,访问令牌的请求参数
|
||||||
|
*
|
||||||
|
* 初始目的:解决 WebSocket 无法通过 header 传参,只能通过 token 参数拼接
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "Token Parameter 不能为空")
|
||||||
|
private String tokenParameter = "token";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mock 模式的开关
|
* mock 模式的开关
|
||||||
|
|
|
@ -129,8 +129,6 @@ public class YudaoWebSecurityConfigurerAdapter {
|
||||||
.antMatchers(buildAppApi("/**")).permitAll()
|
.antMatchers(buildAppApi("/**")).permitAll()
|
||||||
// 1.5 验证码captcha 允许匿名访问
|
// 1.5 验证码captcha 允许匿名访问
|
||||||
.antMatchers("/captcha/get", "/captcha/check").permitAll()
|
.antMatchers("/captcha/get", "/captcha/check").permitAll()
|
||||||
// 1.6 webSocket 允许匿名访问
|
|
||||||
.antMatchers("/websocket/message").permitAll()
|
|
||||||
// ②:每个项目的自定义规则
|
// ②:每个项目的自定义规则
|
||||||
.and().authorizeRequests(registry -> // 下面,循环设置自定义规则
|
.and().authorizeRequests(registry -> // 下面,循环设置自定义规则
|
||||||
authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
|
authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
|
||||||
|
|
|
@ -41,7 +41,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||||
@SuppressWarnings("NullableProblems")
|
@SuppressWarnings("NullableProblems")
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
|
String token = SecurityFrameworkUtils.obtainAuthorization(request,
|
||||||
|
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
|
||||||
if (StrUtil.isNotEmpty(token)) {
|
if (StrUtil.isNotEmpty(token)) {
|
||||||
Integer userType = WebFrameworkUtils.getLoginUserType(request);
|
Integer userType = WebFrameworkUtils.getLoginUserType(request);
|
||||||
try {
|
try {
|
||||||
|
@ -74,7 +75,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||||
return null;
|
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("错误的用户类型");
|
throw new AccessDeniedException("错误的用户类型");
|
||||||
}
|
}
|
||||||
// 构建登录用户
|
// 构建登录用户
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.framework.security.core.util;
|
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.security.core.LoginUser;
|
||||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
@ -20,6 +21,9 @@ import java.util.Collections;
|
||||||
*/
|
*/
|
||||||
public class SecurityFrameworkUtils {
|
public class SecurityFrameworkUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HEADER 认证头 value 的前缀
|
||||||
|
*/
|
||||||
public static final String AUTHORIZATION_BEARER = "Bearer";
|
public static final String AUTHORIZATION_BEARER = "Bearer";
|
||||||
|
|
||||||
private SecurityFrameworkUtils() {}
|
private SecurityFrameworkUtils() {}
|
||||||
|
@ -28,19 +32,23 @@ public class SecurityFrameworkUtils {
|
||||||
* 从请求中,获得认证 Token
|
* 从请求中,获得认证 Token
|
||||||
*
|
*
|
||||||
* @param request 请求
|
* @param request 请求
|
||||||
* @param header 认证 Token 对应的 Header 名字
|
* @param headerName 认证 Token 对应的 Header 名字
|
||||||
|
* @param parameterName 认证 Token 对应的 Parameter 名字
|
||||||
* @return 认证 Token
|
* @return 认证 Token
|
||||||
*/
|
*/
|
||||||
public static String obtainAuthorization(HttpServletRequest request, String header) {
|
public static String obtainAuthorization(HttpServletRequest request,
|
||||||
String authorization = request.getHeader(header);
|
String headerName, String parameterName) {
|
||||||
if (!StringUtils.hasText(authorization)) {
|
// 1. 获得 Token。优先级:Header > Parameter
|
||||||
|
String token = request.getHeader(headerName);
|
||||||
|
if (StrUtil.isEmpty(token)) {
|
||||||
|
token = request.getParameter(parameterName);
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(token)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int index = authorization.indexOf(AUTHORIZATION_BEARER + " ");
|
// 2. 去除 Token 中带的 Bearer
|
||||||
if (index == -1) { // 未找到
|
int index = token.indexOf(AUTHORIZATION_BEARER + " ");
|
||||||
return null;
|
return index >= 0 ? token.substring(index + 7).trim() : token;
|
||||||
}
|
|
||||||
return authorization.substring(index + 7).trim();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -53,7 +53,8 @@ public class AppAuthController {
|
||||||
@PermitAll
|
@PermitAll
|
||||||
@Operation(summary = "登出系统")
|
@Operation(summary = "登出系统")
|
||||||
public CommonResult<Boolean> logout(HttpServletRequest request) {
|
public CommonResult<Boolean> logout(HttpServletRequest request) {
|
||||||
String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
|
String token = SecurityFrameworkUtils.obtainAuthorization(request,
|
||||||
|
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
|
||||||
if (StrUtil.isNotBlank(token)) {
|
if (StrUtil.isNotBlank(token)) {
|
||||||
authService.logout(token);
|
authService.logout(token);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
|
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.controller.admin.auth.vo.*;
|
||||||
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
|
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
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.pojo.CommonResult.success;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
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.getLoginUserId;
|
||||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization;
|
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 认证")
|
@Tag(name = "管理后台 - 认证")
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -76,7 +76,8 @@ public class AuthController {
|
||||||
@Operation(summary = "登出系统")
|
@Operation(summary = "登出系统")
|
||||||
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
|
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
|
||||||
public CommonResult<Boolean> logout(HttpServletRequest request) {
|
public CommonResult<Boolean> logout(HttpServletRequest request) {
|
||||||
String token = obtainAuthorization(request, securityProperties.getTokenHeader());
|
String token = SecurityFrameworkUtils.obtainAuthorization(request,
|
||||||
|
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
|
||||||
if (StrUtil.isNotBlank(token)) {
|
if (StrUtil.isNotBlank(token)) {
|
||||||
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
|
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue