1.【修复】定时任务刷新本地缓存时,无租户上线文,导致查询报错

2. member 模块,统一使用 member 前缀
3. 修改 Spring Security logout 配置,支持多用户类型的退出
pull/2/head
YunaiV 2022-01-29 14:05:06 +08:00
parent 6aca4ae9fd
commit cee7e50720
18 changed files with 63 additions and 55 deletions

View File

@ -1,7 +1,6 @@
{ {
"local": { "local": {
"baseUrl": "http://127.0.0.1:48080/api", "baseUrl": "http://127.0.0.1:48080/api",
"userServerUrl": "http://127.0.0.1:28080/api",
"token": "test1", "token": "test1",
"userApi": "http://127.0.0.1:48080/app-api", "userApi": "http://127.0.0.1:48080/app-api",

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptListReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptListReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dept.SysDeptDO; import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dept.SysDeptDO;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -28,6 +29,7 @@ public interface SysDeptMapper extends BaseMapperX<SysDeptDO> {
return selectCount(SysDeptDO::getParentId, parentId); return selectCount(SysDeptDO::getParentId, parentId);
} }
@InterceptorIgnore(tenantLine = "on") // 该方法忽略多租户。原因:该方法被异步 task 调用,此时获取不到租户编号
default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) { default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) {
return selectOne(new LambdaQueryWrapper<SysDeptDO>().select(SysDeptDO::getId) return selectOne(new LambdaQueryWrapper<SysDeptDO>().select(SysDeptDO::getId)
.gt(SysDeptDO::getUpdateTime, maxUpdateTime).last(SqlConstants.LIMIT1)) != null; .gt(SysDeptDO::getUpdateTime, maxUpdateTime).last(SqlConstants.LIMIT1)) != null;

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.framework.security.config; package cn.iocoder.yudao.framework.security.config;
import cn.hutool.core.util.StrUtil;
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.filter.JWTAuthenticationTokenFilter; import cn.iocoder.yudao.framework.security.core.filter.JWTAuthenticationTokenFilter;
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
@ -21,8 +22,10 @@ import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/** /**
* Spring Security * Spring Security
@ -106,6 +109,7 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
*/ */
@Override @Override
protected void configure(HttpSecurity httpSecurity) throws Exception { protected void configure(HttpSecurity httpSecurity) throws Exception {
// 登出
httpSecurity httpSecurity
// 开启跨域 // 开启跨域
.cors().and() .cors().and()
@ -117,7 +121,9 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
// 一堆自定义的 Spring Security 处理器 // 一堆自定义的 Spring Security 处理器
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint) .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler).and() .accessDeniedHandler(accessDeniedHandler).and()
.logout().logoutUrl(buildAdminApi("/logout")).logoutSuccessHandler(logoutSuccessHandler); // 登出 // 登出地址的配置
.logout().logoutSuccessHandler(logoutSuccessHandler).logoutRequestMatcher(request -> // 匹配多种用户类型的登出
StrUtil.equalsAny(request.getRequestURI(), buildAdminApi("/logout"), buildAppApi("/member/logout")));
// 设置每个请求的权限 ①:全局共享规则 // 设置每个请求的权限 ①:全局共享规则
httpSecurity.authorizeRequests() httpSecurity.authorizeRequests()

View File

@ -41,6 +41,19 @@ public class SecurityFrameworkUtils {
return authorization.substring(index + 7).trim(); return authorization.substring(index + 7).trim();
} }
/**
*
*
* @return
*/
public static Authentication getAuthentication() {
SecurityContext context = SecurityContextHolder.getContext();
if (context == null) {
return null;
}
return context.getAuthentication();
}
/** /**
* *
* *
@ -48,11 +61,7 @@ public class SecurityFrameworkUtils {
*/ */
@Nullable @Nullable
public static LoginUser getLoginUser() { public static LoginUser getLoginUser() {
SecurityContext context = SecurityContextHolder.getContext(); Authentication authentication = getAuthentication();
if (context == null) {
return null;
}
Authentication authentication = context.getAuthentication();
if (authentication == null) { if (authentication == null) {
return null; return null;
} }
@ -88,16 +97,22 @@ public class SecurityFrameworkUtils {
* @param request * @param request
*/ */
public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) { public static void setLoginUser(LoginUser loginUser, HttpServletRequest request) {
// 创建 UsernamePasswordAuthenticationToken 对象 // 创建 Authentication并设置到上下文
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( Authentication authentication = buildAuthentication(loginUser, request);
loginUser, null, loginUser.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication);
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// 设置到上下文
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
// 额外设置到 request 中,用于 ApiAccessLogFilter 可以获取到用户编号; // 额外设置到 request 中,用于 ApiAccessLogFilter 可以获取到用户编号;
// 原因是Spring Security 的 Filter 在 ApiAccessLogFilter 后面,在它记录访问日志时,线上上下文已经没有用户编号等信息 // 原因是Spring Security 的 Filter 在 ApiAccessLogFilter 后面,在它记录访问日志时,线上上下文已经没有用户编号等信息
WebFrameworkUtils.setLoginUserId(request, loginUser.getId()); WebFrameworkUtils.setLoginUserId(request, loginUser.getId());
WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType()); WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType());
} }
private static Authentication buildAuthentication(LoginUser loginUser, HttpServletRequest request) {
// 创建 UsernamePasswordAuthenticationToken 对象
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
return authenticationToken;
}
} }

View File

@ -10,17 +10,11 @@ import cn.iocoder.yudao.coreservice.modules.bpm.api.group.BpmUserGroupServiceApi
import cn.iocoder.yudao.coreservice.modules.system.service.dept.SysDeptCoreService; import cn.iocoder.yudao.coreservice.modules.system.service.dept.SysDeptCoreService;
import cn.iocoder.yudao.coreservice.modules.system.service.permission.SysPermissionCoreService; import cn.iocoder.yudao.coreservice.modules.system.service.permission.SysPermissionCoreService;
import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService; import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import org.activiti.api.runtime.shared.identity.UserGroupManager; import org.activiti.api.runtime.shared.identity.UserGroupManager;
import org.activiti.core.common.spring.identity.ActivitiUserGroupManagerImpl;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer; import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetailsService;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;

View File

@ -1,5 +1,5 @@
### 请求 /login 接口 => 成功 ### 请求 /login 接口 => 成功
POST {{userApi}}/login POST {{userApi}}/member/login
Content-Type: application/json Content-Type: application/json
tenant-id: {{userTenentId}} tenant-id: {{userTenentId}}
@ -9,8 +9,9 @@ tenant-id: {{userTenentId}}
} }
### 请求 /send-sms-code 接口 => 成功 ### 请求 /send-sms-code 接口 => 成功
POST {{userServerUrl}}/send-sms-code POST {{userApi}}/member/send-sms-code
Content-Type: application/json Content-Type: application/json
tenant-id: {{userTenentId}}
{ {
"mobile": "15601691399", "mobile": "15601691399",
@ -18,8 +19,9 @@ Content-Type: application/json
} }
### 请求 /sms-login 接口 => 成功 ### 请求 /sms-login 接口 => 成功
POST {{userServerUrl}}/sms-login POST {{userApi}}/member/sms-login
Content-Type: application/json Content-Type: application/json
tenant-id: {{userTenentId}}
{ {
"mobile": "15601691301", "mobile": "15601691301",
@ -27,6 +29,7 @@ Content-Type: application/json
} }
### 请求 /logout 接口 => 成功 ### 请求 /logout 接口 => 成功
POST {{userServerUrl}}/logout POST {{userApi}}/member/logout
Content-Type: application/json Content-Type: application/json
Authorization: Bearer c1b76bdaf2c146c581caa4d7fd81ee66 Authorization: Bearer c1b76bdaf2c146c581caa4d7fd81ee66
tenant-id: {{userTenentId}}

View File

@ -5,6 +5,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.core.annotations.PreAuthenticated; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
import cn.iocoder.yudao.module.member.service.auth.AuthService; import cn.iocoder.yudao.module.member.service.auth.AuthService;
import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService; import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService;
@ -13,6 +14,7 @@ import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -26,7 +28,7 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
@Api(tags = "APP 端 - 认证") @Api(tags = "APP 端 - 认证")
@RestController @RestController
@RequestMapping("/") @RequestMapping("/member/")
@Validated @Validated
@Slf4j @Slf4j
public class AppAuthController { public class AppAuthController {
@ -39,6 +41,9 @@ public class AppAuthController {
@Resource @Resource
private SysSocialCoreService socialService; private SysSocialCoreService socialService;
@Resource
private LogoutSuccessHandler logoutSuccessHandler;
@PostMapping("/login") @PostMapping("/login")
@ApiOperation("使用手机 + 密码登录") @ApiOperation("使用手机 + 密码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.userserver.modules.weixin.controller.mp; package cn.iocoder.yudao.module.member.controller.app.weixin;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
@ -19,10 +19,10 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "微信公众号") @Api(tags = "微信公众号")
@RestController @RestController
@RequestMapping("/wx/mp") @RequestMapping("/member/wx-mp")
@Validated @Validated
@Slf4j @Slf4j
public class WxMpController { public class AppWxMpController {
@Resource @Resource
private WxMpService mpService; private WxMpService mpService;

View File

@ -16,7 +16,7 @@ import java.util.Date;
* *
* @author * @author
*/ */
@TableName(value = "mbr_user", autoResultMap = true) @TableName(value = "member_user", autoResultMap = true)
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Builder @Builder

View File

@ -4,6 +4,6 @@
* 2. redisRedis CRUD * 2. redisRedis CRUD
* 3. mysqlMySQL CRUD * 3. mysqlMySQL CRUD
* *
* MySQL mbr_ * MySQL member_
*/ */
package cn.iocoder.yudao.module.member.dal; package cn.iocoder.yudao.module.member.dal;

View File

@ -1 +1,8 @@
/**
* member
*
*
* 1. Controller URL /member/ Module
* 2. DataObject member_ 便
*/
package cn.iocoder.yudao.module.member; package cn.iocoder.yudao.module.member;

View File

@ -1,2 +1,2 @@
-- mbr DB -- mbr DB
DELETE FROM "mbr_user"; DELETE FROM "member_user";

View File

@ -1,5 +1,5 @@
-- mbr DB -- mbr DB
CREATE TABLE IF NOT EXISTS "mbr_user" ( CREATE TABLE IF NOT EXISTS "member_user" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '', "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '',
"nickname" varchar(30) NOT NULL DEFAULT '' COMMENT '', "nickname" varchar(30) NOT NULL DEFAULT '' COMMENT '',
"avatar" varchar(255) NOT NULL DEFAULT '' COMMENT '', "avatar" varchar(255) NOT NULL DEFAULT '' COMMENT '',

View File

@ -1,14 +0,0 @@
package cn.iocoder.yudao.userserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package} 和 ${yudao.core-service.base-package}
@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}", "${yudao.core-service.base-package}"})
public class UserServerApplication {
public static void main(String[] args) {
SpringApplication.run(UserServerApplication.class, args);
}
}

View File

@ -1,7 +0,0 @@
/**
* weixin
*
*
* wx
*/
package cn.iocoder.yudao.userserver.modules.weixin;

View File

@ -37,8 +37,6 @@ mybatis-plus:
mapper-locations: classpath*:mapper/*.xml mapper-locations: classpath*:mapper/*.xml
type-aliases-package: ${yudao.info.base-package}.modules.*.dal.dataobject, ${yudao.core-service.base-package}.modules.*.dal.dataobject type-aliases-package: ${yudao.info.base-package}.modules.*.dal.dataobject, ${yudao.core-service.base-package}.modules.*.dal.dataobject
--- #################### 芋道相关配置 #################### --- #################### 芋道相关配置 ####################
yudao: yudao:
@ -67,5 +65,4 @@ yudao:
- cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants - cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants
- cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants - cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants
debug: false debug: false

View File

@ -23,6 +23,7 @@
### 🐞 Bug Fixes ### 🐞 Bug Fixes
*【修复】用户无权限访问 指定 API 时,未返回 FORBIDDEN 结果码 *【修复】用户无权限访问 指定 API 时,未返回 FORBIDDEN 结果码
*【修复】定时任务刷新本地缓存时,无租户上线文,导致查询报错
### 🔨 Dependency Upgrades ### 🔨 Dependency Upgrades