mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-23 07:41:53 +08:00
简化 mock login 模拟登录的实现,由 TokenAuthenticationFilter 直接实现
This commit is contained in:
parent
73bf0b6f4f
commit
baadb5a937
@ -1,7 +1,7 @@
|
|||||||
package cn.iocoder.yudao.framework.tenant.core.web;
|
package cn.iocoder.yudao.framework.tenant.core.web;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
@ -24,9 +24,9 @@ public class TenantContextWebFilter extends OncePerRequestFilter {
|
|||||||
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 tenantId = request.getHeader(HEADER_TENANT_ID);
|
Long tenantId = WebFrameworkUtils.getTenantId(request);
|
||||||
if (StrUtil.isNotEmpty(tenantId)) {
|
if (tenantId != null) {
|
||||||
TenantContextHolder.setTenantId(Long.valueOf(tenantId));
|
TenantContextHolder.setTenantId(tenantId);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
|
@ -105,17 +105,6 @@ public class MultiUserDetailsAuthenticationProvider extends AbstractUserDetailsA
|
|||||||
return selectService(request).verifyTokenAndRefresh(token);
|
return selectService(request).verifyTokenAndRefresh(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 模拟指定用户编号的 LoginUser
|
|
||||||
*
|
|
||||||
* @param request 请求
|
|
||||||
* @param userId 用户编号
|
|
||||||
* @return 登录用户
|
|
||||||
*/
|
|
||||||
public LoginUser mockLogin(HttpServletRequest request, Long userId) {
|
|
||||||
return selectService(request).mockLogin(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基于 token 退出登录
|
* 基于 token 退出登录
|
||||||
*
|
*
|
||||||
|
@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.security.core.LoginUser;
|
|||||||
import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
|
import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||||
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
@ -38,12 +39,13 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
|
String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
|
||||||
if (StrUtil.isNotEmpty(token)) {
|
if (StrUtil.isNotEmpty(token)) {
|
||||||
|
Integer userType = WebFrameworkUtils.getLoginUserType(request);
|
||||||
try {
|
try {
|
||||||
// 验证 token 有效性
|
// 验证 token 有效性
|
||||||
LoginUser loginUser = authenticationProvider.verifyTokenAndRefresh(request, token);
|
LoginUser loginUser = authenticationProvider.verifyTokenAndRefresh(request, token);
|
||||||
// 模拟 Login 功能,方便日常开发调试
|
// 模拟 Login 功能,方便日常开发调试
|
||||||
if (loginUser == null) {
|
if (loginUser == null) {
|
||||||
loginUser = mockLoginUser(request, token);
|
loginUser = mockLoginUser(request, token, userType);
|
||||||
}
|
}
|
||||||
// 设置当前用户
|
// 设置当前用户
|
||||||
if (loginUser != null) {
|
if (loginUser != null) {
|
||||||
@ -67,9 +69,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
*
|
*
|
||||||
* @param request 请求
|
* @param request 请求
|
||||||
* @param token 模拟的 token,格式为 {@link SecurityProperties#getMockSecret()} + 用户编号
|
* @param token 模拟的 token,格式为 {@link SecurityProperties#getMockSecret()} + 用户编号
|
||||||
|
* @param userType 用户类型
|
||||||
* @return 模拟的 LoginUser
|
* @return 模拟的 LoginUser
|
||||||
*/
|
*/
|
||||||
private LoginUser mockLoginUser(HttpServletRequest request, String token) {
|
private LoginUser mockLoginUser(HttpServletRequest request, String token, Integer userType) {
|
||||||
if (!securityProperties.getMockEnable()) {
|
if (!securityProperties.getMockEnable()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -77,8 +80,10 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
if (!token.startsWith(securityProperties.getMockSecret())) {
|
if (!token.startsWith(securityProperties.getMockSecret())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// 构建模拟用户
|
||||||
Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length()));
|
Long userId = Long.valueOf(token.substring(securityProperties.getMockSecret().length()));
|
||||||
return authenticationProvider.mockLogin(request, userId);
|
return new LoginUser().setId(userId).setUserType(userType)
|
||||||
|
.setTenantId(WebFrameworkUtils.getTenantId(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,6 @@ public interface SecurityAuthFrameworkService extends UserDetailsService {
|
|||||||
*/
|
*/
|
||||||
LoginUser verifyTokenAndRefresh(String token);
|
LoginUser verifyTokenAndRefresh(String token);
|
||||||
|
|
||||||
/**
|
|
||||||
* 模拟指定用户编号的 LoginUser
|
|
||||||
*
|
|
||||||
* @param userId 用户编号
|
|
||||||
* @return 登录用户
|
|
||||||
*/
|
|
||||||
LoginUser mockLogin(Long userId);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基于 token 退出登录
|
* 基于 token 退出登录
|
||||||
*
|
*
|
||||||
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.web.core.filter.DemoFilter;
|
|||||||
import cn.iocoder.yudao.framework.web.core.filter.XssFilter;
|
import cn.iocoder.yudao.framework.web.core.filter.XssFilter;
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||||
import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler;
|
import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler;
|
||||||
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
@ -65,6 +66,13 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
|
|||||||
return new GlobalResponseBodyHandler();
|
return new GlobalResponseBodyHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@SuppressWarnings("InstantiationOfUtilityClass")
|
||||||
|
public WebFrameworkUtils webFrameworkUtils(WebProperties webProperties) {
|
||||||
|
// 由于 WebFrameworkUtils 需要使用到 webProperties 属性,所以注册为一个 Bean
|
||||||
|
return new WebFrameworkUtils(webProperties);
|
||||||
|
}
|
||||||
|
|
||||||
// ========== Filter 相关 ==========
|
// ========== Filter 相关 ==========
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package cn.iocoder.yudao.framework.web.core.util;
|
package cn.iocoder.yudao.framework.web.core.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
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.web.config.WebProperties;
|
||||||
import org.springframework.web.context.request.RequestAttributes;
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
@ -21,16 +23,43 @@ public class WebFrameworkUtils {
|
|||||||
|
|
||||||
private static final String REQUEST_ATTRIBUTE_COMMON_RESULT = "common_result";
|
private static final String REQUEST_ATTRIBUTE_COMMON_RESULT = "common_result";
|
||||||
|
|
||||||
|
private static final String HEADER_TENANT_ID = "tenant-id";
|
||||||
|
|
||||||
|
private static WebProperties properties;
|
||||||
|
|
||||||
|
public WebFrameworkUtils(WebProperties webProperties) {
|
||||||
|
WebFrameworkUtils.properties = webProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得租户编号,从 header 中
|
||||||
|
* 考虑到其它 framework 组件也会使用到租户编号,所以不得不放在 WebFrameworkUtils 统一提供
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @return 租户编号
|
||||||
|
*/
|
||||||
|
public static Long getTenantId(HttpServletRequest request) {
|
||||||
|
String tenantId = request.getHeader(HEADER_TENANT_ID);
|
||||||
|
return StrUtil.isNotEmpty(tenantId) ? Long.valueOf(tenantId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void setLoginUserId(ServletRequest request, Long userId) {
|
public static void setLoginUserId(ServletRequest request, Long userId) {
|
||||||
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID, userId);
|
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置用户类型
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @param userType 用户类型
|
||||||
|
*/
|
||||||
public static void setLoginUserType(ServletRequest request, Integer userType) {
|
public static void setLoginUserType(ServletRequest request, Integer userType) {
|
||||||
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE, userType);
|
request.setAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE, userType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得当前用户的编号,从请求中
|
* 获得当前用户的编号,从请求中
|
||||||
|
* 注意:该方法仅限于 framework 框架使用!!!
|
||||||
*
|
*
|
||||||
* @param request 请求
|
* @param request 请求
|
||||||
* @return 用户编号
|
* @return 用户编号
|
||||||
@ -43,7 +72,8 @@ public class WebFrameworkUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得当前用户的类型,从请求中
|
* 获得当前用户的类型
|
||||||
|
* 注意:该方法仅限于 web 相关的 framework 组件使用!!!
|
||||||
*
|
*
|
||||||
* @param request 请求
|
* @param request 请求
|
||||||
* @return 用户编号
|
* @return 用户编号
|
||||||
@ -52,7 +82,19 @@ public class WebFrameworkUtils {
|
|||||||
if (request == null) {
|
if (request == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE);
|
// 1. 优先,从 Attribute 中获取
|
||||||
|
Integer userType = (Integer) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_TYPE);
|
||||||
|
if (userType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 2. 其次,基于 URL 前缀的约定
|
||||||
|
if (request.getRequestURI().startsWith(properties.getAdminApi().getPrefix())) {
|
||||||
|
return UserTypeEnum.ADMIN.getValue();
|
||||||
|
}
|
||||||
|
if (request.getRequestURI().startsWith(properties.getAppApi().getPrefix())) {
|
||||||
|
return UserTypeEnum.MEMBER.getValue();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer getLoginUserType() {
|
public static Integer getLoginUserType() {
|
||||||
|
@ -211,21 +211,6 @@ public class MemberAuthServiceImpl implements MemberAuthService {
|
|||||||
return userSessionApi.getLoginUser(token);
|
return userSessionApi.getLoginUser(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public LoginUser mockLogin(Long userId) {
|
|
||||||
// 获取用户编号对应的 UserDO
|
|
||||||
MemberUserDO user = userService.getUser(userId);
|
|
||||||
if (user == null) {
|
|
||||||
throw new UsernameNotFoundException(String.valueOf(userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行登陆
|
|
||||||
createLoginLog(userId, user.getMobile(), LoginLogTypeEnum.LOGIN_MOCK, LoginResultEnum.SUCCESS);
|
|
||||||
|
|
||||||
// 创建 LoginUser 对象
|
|
||||||
return buildLoginUser(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void logout(String token) {
|
public void logout(String token) {
|
||||||
// 查询用户信息
|
// 查询用户信息
|
||||||
|
@ -12,7 +12,6 @@ public enum LoginLogTypeEnum {
|
|||||||
|
|
||||||
LOGIN_USERNAME(100), // 使用账号登录
|
LOGIN_USERNAME(100), // 使用账号登录
|
||||||
LOGIN_SOCIAL(101), // 使用社交登录
|
LOGIN_SOCIAL(101), // 使用社交登录
|
||||||
LOGIN_MOCK(102), // 使用 Mock 登录
|
|
||||||
LOGIN_MOBILE(103), // 使用手机登陆
|
LOGIN_MOBILE(103), // 使用手机登陆
|
||||||
LOGIN_SMS(104), // 使用短信登陆
|
LOGIN_SMS(104), // 使用短信登陆
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
### 请求 /login 接口 => 成功
|
### 请求 /login 接口 => 成功
|
||||||
POST {{baseUrl}}/system/login
|
POST {{baseUrl}}/system/auth/login
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
tenant-id: {{adminTenentId}}
|
tenant-id: {{adminTenentId}}
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ tenant-id: {{adminTenentId}}
|
|||||||
}
|
}
|
||||||
|
|
||||||
### 请求 /login 接口 => 成功(无验证码)
|
### 请求 /login 接口 => 成功(无验证码)
|
||||||
POST {{baseUrl}}/system/login
|
POST {{baseUrl}}/system/auth/login
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
tenant-id: {{adminTenentId}}
|
tenant-id: {{adminTenentId}}
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ tenant-id: {{adminTenentId}}
|
|||||||
}
|
}
|
||||||
|
|
||||||
### 请求 /get-permission-info 接口 => 成功
|
### 请求 /get-permission-info 接口 => 成功
|
||||||
GET {{baseUrl}}/system/get-permission-info
|
GET {{baseUrl}}/system/auth/get-permission-info
|
||||||
Authorization: Bearer {{token}}
|
Authorization: Bearer {{token}}
|
||||||
tenant-id: {{adminTenentId}}
|
tenant-id: {{adminTenentId}}
|
||||||
|
|
||||||
|
@ -82,19 +82,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
|||||||
return AuthConvert.INSTANCE.convert2(user);
|
return AuthConvert.INSTANCE.convert2(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public LoginUser mockLogin(Long userId) {
|
|
||||||
// 获取用户编号对应的 AdminUserDO
|
|
||||||
AdminUserDO user = userService.getUser(userId);
|
|
||||||
if (user == null) {
|
|
||||||
throw new UsernameNotFoundException(String.valueOf(userId));
|
|
||||||
}
|
|
||||||
createLoginLog(userId, user.getUsername(), LoginLogTypeEnum.LOGIN_MOCK, LoginResultEnum.SUCCESS);
|
|
||||||
|
|
||||||
// 创建 LoginUser 对象
|
|
||||||
return buildLoginUser(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String login(AuthLoginReqVO reqVO, String userIp, String userAgent) {
|
public String login(AuthLoginReqVO reqVO, String userIp, String userAgent) {
|
||||||
// 判断验证码是否正确
|
// 判断验证码是否正确
|
||||||
|
@ -96,32 +96,6 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
|
|||||||
username); // 异常提示为 username
|
username); // 异常提示为 username
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMockLogin_success() {
|
|
||||||
// 准备参数
|
|
||||||
Long userId = randomLongId();
|
|
||||||
// mock 方法 01
|
|
||||||
AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId));
|
|
||||||
when(userService.getUser(eq(userId))).thenReturn(user);
|
|
||||||
|
|
||||||
// 调用
|
|
||||||
LoginUser loginUser = authService.mockLogin(userId);
|
|
||||||
// 断言
|
|
||||||
AssertUtils.assertPojoEquals(user, loginUser, "updateTime");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMockLogin_userNotFound() {
|
|
||||||
// 准备参数
|
|
||||||
Long userId = randomLongId();
|
|
||||||
// mock 方法
|
|
||||||
|
|
||||||
// 调用, 并断言异常
|
|
||||||
assertThrows(UsernameNotFoundException.class, // 抛出 UsernameNotFoundException 异常
|
|
||||||
() -> authService.mockLogin(userId),
|
|
||||||
String.valueOf(userId)); // 异常提示为 userId
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLogin_captchaNotFound() {
|
public void testLogin_captchaNotFound() {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
|
Loading…
Reference in New Issue
Block a user