提交
48
.cursor/rules/1.mdc
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Your rule content
|
||||
#角色
|
||||
你是一名精通开发的高级工程师,拥有10年以上的应用开发经验,熟悉*等开发工具和技术栈。
|
||||
你的任务是帮助用户设计和开发易用且易于推护的 *** 应用。始终遵循最佳实践,并坚持干净代码和健壮架构的原则。
|
||||
|
||||
#目标
|
||||
你的目标是以用户容易理解的方式帮助他们完成“应用的设计和开发工作,确保应用功能完善、性能优异、用户体验良好。
|
||||
|
||||
#要求
|
||||
在理解用户需求、设计UI、编写代码、解决问题和项目选代优化时,你应该始终遵循以下原则:
|
||||
|
||||
|
||||
##需求理解
|
||||
-充分理解用户需求,站在用户角度思考,分析需求是否存在缺漏,并与用户讨论完善需求;
|
||||
-选择最简单的解决方案来满足用户需求,避免过度设计。
|
||||
##UI和样式设计
|
||||
-使用现代UI框架进行样式设计(例如***,这里可以根据不同开发项目仔纽展开,比如使用哪些视觉规范或者UI框架,没有的话也可以不用过多展开);
|
||||
-在不同平台上实现一致的设计和响应式模式
|
||||
##代码编写
|
||||
技术选型:根据项目需求选择合适的技术栈(例如***,这里需要仔细展开,比如介招某个技术栈用在什么地方,以及要遵循什么最佳实践)
|
||||
代码结构:强调代码的清晰性、模块化、可维护性,遵循最佳实践(如DRY原则、最小权限原则、响应式设计等)
|
||||
-代码安全性:在编写代码时,始终考虑安全性,避免引入漏洞,确保用户输入的安全处理
|
||||
-性能优化:优化代码的性能,减少资源占用,提升加载速度,确保项目的高效运行
|
||||
-测试与文档:编写单元测试,确保代码的健壮性,并提供清晰的中文注释和文档。方便后续阅读和维护
|
||||
##问题解决
|
||||
-全面阅读相关代码,理解***应用的工作原理
|
||||
-根据用户的反馈分析问题的原因,提出解决问题的思路
|
||||
-确保每次代码变更不会破坏现有功能,且尽可能保持最小的改动
|
||||
##迭代优化
|
||||
与用户保持密切沟通,根据反读调整功能和设计,确保应用符合用户需求
|
||||
在不确定需求时,主动询问用户以澄清需求或技术细节
|
||||
##方法论
|
||||
-系统2思维:以分析严谨的方式解决问题。将需求分解为更小、可管理的部分,并在实施前仔细考虑每一步
|
||||
思维树:评估多种可能的解决方案及其后果。使用结构化的方法探索不同的路径。并选择最优的解决方案
|
||||
-选代改进:在最终确定代码之前,考虑改进、边缘情况和优化。通过潜在增强的迭代,确保最终解决方案是健壮的
|
||||
|
||||
|
||||
2
.lingma/rules/project_rule.md
Normal file
@@ -0,0 +1,2 @@
|
||||
**添加规则文件可帮助模型精准理解你的编码偏好,如框架、代码风格等**
|
||||
**规则文件只对当前工程生效,单文件限制10000字符。如果无需将该文件提交到远程 Git 仓库,请将其添加到 .gitignore**
|
||||
BIN
logs/gateway-server.log.2025-04-22.0.gz
Normal file
BIN
logs/system-server.log.2025-04-22.0.gz
Normal file
@@ -81,6 +81,48 @@
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- Sa-Token 权限认证(Reactor响应式集成),在线文档:https://sa-token.cc -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-reactor-spring-boot3-starter</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 插件:整合SSO -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-sso</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token OAuth2.0 模块 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-oauth2</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-redis-jackson</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.dtflys.forest</groupId>
|
||||
<artifactId>forest-spring-boot-starter</artifactId>
|
||||
<version>1.5.26</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- 统一依赖管理 -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
|
||||
@@ -93,7 +93,7 @@ public class CommonResult<T> implements Serializable {
|
||||
|
||||
// ========= 和 Exception 异常体系集成 =========
|
||||
|
||||
/**
|
||||
/**
|
||||
* 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
|
||||
*/
|
||||
public void checkError() throws ServiceException {
|
||||
|
||||
@@ -45,6 +45,23 @@
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-reactor-spring-boot3-starter</artifactId>
|
||||
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-redis-jackson</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 注册中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
@@ -68,6 +85,8 @@
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
package com.tashow.cloud.gateway;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.tashow.cloud.gateway.filter.security;
|
||||
|
||||
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* [Sa-Token 权限认证] 配置类
|
||||
* @author click33
|
||||
*/
|
||||
@Configuration
|
||||
public class SaTokenConfigure {
|
||||
// 注册 Sa-Token全局过滤器
|
||||
@Bean
|
||||
public SaReactorFilter getSaReactorFilter() {
|
||||
return new SaReactorFilter()
|
||||
// 拦截地址
|
||||
.addInclude("/**") /* 拦截全部path */
|
||||
// 开放地址
|
||||
.addExclude("/favicon.ico")
|
||||
// 鉴权方法:每次访问进入
|
||||
.setAuth(obj -> {
|
||||
// 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
|
||||
SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());
|
||||
|
||||
// 权限认证 -- 不同模块, 校验不同权限
|
||||
SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
|
||||
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
|
||||
SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
|
||||
SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
|
||||
|
||||
// 更多匹配 ... */
|
||||
})
|
||||
// 异常处理方法:每次setAuth函数出现异常时进入
|
||||
.setError(e -> {
|
||||
return SaResult.error(e.getMessage());
|
||||
})
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.tashow.cloud.gateway.filter.security;
|
||||
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义权限验证接口扩展
|
||||
*/
|
||||
@Component
|
||||
public class StpInterfaceImpl implements StpInterface {
|
||||
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||
// 本 list 仅做模拟,实际项目中要根据具体业务逻辑来查询权限
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add("101");
|
||||
list.add("user.add");
|
||||
list.add("user.update");
|
||||
list.add("user.get");
|
||||
// list.add("user.delete");
|
||||
list.add("art.*");
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginType) {
|
||||
// 本 list 仅做模拟,实际项目中要根据具体业务逻辑来查询角色
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add("admin");
|
||||
list.add("super-admin");
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,6 @@
|
||||
<modules>
|
||||
<module>tashow-module-system</module>
|
||||
<module>tashow-module-infra</module>
|
||||
<module>tashow-module-user</module>
|
||||
<module>tashow-module-sso</module>
|
||||
</modules>
|
||||
|
||||
|
||||
@@ -37,20 +37,20 @@
|
||||
</dependency>-->
|
||||
|
||||
<!-- 业务组件 -->
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-data-permission</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.tashow.cloud</groupId>-->
|
||||
<!-- <artifactId>tashow-data-permission</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-framework-tenant</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-framework-security</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.tashow.cloud</groupId>-->
|
||||
<!-- <artifactId>tashow-framework-security</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
@@ -137,47 +137,50 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-reactor-spring-boot3-starter</artifactId>
|
||||
<version>1.42.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
<version>1.42.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 插件:整合SSO -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-sso</artifactId>
|
||||
<version>1.42.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token OAuth2.0 模块 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-oauth2</artifactId>
|
||||
<version>1.42.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-redis-jackson</artifactId>
|
||||
<version>1.42.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.dtflys.forest</groupId>
|
||||
<artifactId>forest-spring-boot-starter</artifactId>
|
||||
<version>1.5.26</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-alone-redis</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
<!-- 视图引擎(在前后端不分离模式下提供视图支持) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -6,10 +6,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class TashowModuleSsoBizApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TashowModuleSsoBizApplication.class, args);
|
||||
System.out.println("\nSa-Token-OAuth2 Server端启动成功,配置如下:");
|
||||
System.out.println("Sa-Token-OAuth2 Server端启动成功,配置如下:");
|
||||
System.out.println(SaOAuth2Manager.getServerConfig());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.tashow.cloud.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* MyBatis Plus配置类
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan("com.tashow.cloud.mapper")
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
/**
|
||||
* 配置分页插件
|
||||
*/
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
// 添加分页插件
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
package com.tashow.cloud.controller;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.oauth2.config.SaOAuth2ServerConfig;
|
||||
import cn.dev33.satoken.oauth2.consts.GrantType;
|
||||
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
|
||||
import cn.dev33.satoken.oauth2.processor.SaOAuth2ServerProcessor;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.tashow.cloud.model.SystemUser;
|
||||
import com.tashow.cloud.service.SystemUserService;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Sa-Token OAuth2 Server端 控制器
|
||||
*/
|
||||
@RestController
|
||||
public class SaOAuth2ServerController {
|
||||
|
||||
@Autowired
|
||||
private SystemUserService userService;
|
||||
|
||||
// OAuth2-Server 端:处理所有 OAuth2 相关请求
|
||||
@RequestMapping("/oauth2/*")
|
||||
@PermitAll
|
||||
public Object request() {
|
||||
System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl());
|
||||
return SaOAuth2ServerProcessor.instance.dister();
|
||||
}
|
||||
|
||||
// Sa-Token OAuth2 定制化配置
|
||||
@Autowired
|
||||
@PermitAll
|
||||
public void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) {
|
||||
|
||||
// 添加 client 信息
|
||||
oauth2Server.addClient(
|
||||
new SaClientModel()
|
||||
.setClientId("1001") // client id
|
||||
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee") // client 秘钥
|
||||
.addAllowRedirectUris("*") // 所有允许授权的 url
|
||||
.addContractScopes("openid", "userid", "userinfo") // 所有签约的权限
|
||||
.addAllowGrantTypes( // 所有允许的授权模式
|
||||
GrantType.authorization_code, // 授权码式
|
||||
GrantType.implicit, // 隐式式
|
||||
GrantType.refresh_token, // 刷新令牌
|
||||
GrantType.password, // 密码式
|
||||
GrantType.client_credentials // 客户端模式
|
||||
)
|
||||
);
|
||||
|
||||
// 可以添加更多 client 信息,只要保持 clientId 唯一就行了
|
||||
// oauth2Server.addClient(...)
|
||||
|
||||
// 配置:未登录时返回的View
|
||||
oauth2Server.notLoginView = () -> {
|
||||
String msg = "当前会话在OAuth-Server端尚未登录,请先访问"
|
||||
+ "<a href='/oauth2/login-page' target='_blank'>登录页面</a>"
|
||||
+ "或 <a href='/sso/register-page' target='_blank'>注册用户</a>"
|
||||
+ ",进行登录之后,刷新页面开始授权";
|
||||
return msg;
|
||||
};
|
||||
|
||||
// 配置:登录处理函数
|
||||
oauth2Server.doLoginHandle = (name, pwd) -> {
|
||||
// 从数据库查询用户
|
||||
SystemUser user = userService.getUserByUsername(name);
|
||||
|
||||
// 验证用户是否存在且密码是否正确
|
||||
if(user != null && userService.validatePassword(pwd, user.getPassword())) {
|
||||
// 用户状态检查
|
||||
if(user.getStatus() != 0) {
|
||||
return SaResult.error("账号已被禁用");
|
||||
}
|
||||
|
||||
// 登录成功,记录用户IP
|
||||
StpUtil.login(user.getId());
|
||||
|
||||
// 获取当前的HTTP请求对象
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
String ip = "unknown";
|
||||
if (attributes != null) {
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
ip = getClientIp(request);
|
||||
}
|
||||
|
||||
userService.updateLoginInfo(user.getId(), ip);
|
||||
|
||||
return SaResult.ok();
|
||||
}
|
||||
return SaResult.error("账号名或密码错误");
|
||||
};
|
||||
|
||||
// 配置:确认授权时返回的 view
|
||||
oauth2Server.confirmView = (clientId, scopes) -> {
|
||||
String scopeStr = SaFoxUtil.convertListToString(scopes);
|
||||
String yesCode =
|
||||
"fetch('/oauth2/doConfirm?client_id=" + clientId + "&scope=" + scopeStr + "', {method: 'POST'})" +
|
||||
".then(res => res.json())" +
|
||||
".then(res => location.reload())";
|
||||
String res = "<p>应用 " + clientId + " 请求授权:" + scopeStr + ",是否同意?</p>"
|
||||
+ "<p>" +
|
||||
" <button onclick=\"" + yesCode + "\">同意</button>" +
|
||||
" <button onclick='history.back()'>拒绝</button>" +
|
||||
"</p>";
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端真实IP地址
|
||||
*/
|
||||
private String getClientIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("X-Real-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
// 多个代理的情况,第一个IP为客户端真实IP
|
||||
if (ip != null && ip.indexOf(",") > 0) {
|
||||
ip = ip.substring(0, ip.indexOf(","));
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录页面接口 - 返回登录页面HTML
|
||||
*/
|
||||
@GetMapping("/oauth2/login-page")
|
||||
@PermitAll
|
||||
public Object loginPage() {
|
||||
String html = "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"zh-CN\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>OAuth2登录</title>\n" +
|
||||
" <style>\n" +
|
||||
" body {\n" +
|
||||
" font-family: Arial, sans-serif;\n" +
|
||||
" display: flex;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" align-items: center;\n" +
|
||||
" height: 100vh;\n" +
|
||||
" margin: 0;\n" +
|
||||
" background-color: #f5f5f5;\n" +
|
||||
" }\n" +
|
||||
" .login-container {\n" +
|
||||
" background-color: white;\n" +
|
||||
" padding: 30px;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n" +
|
||||
" width: 350px;\n" +
|
||||
" }\n" +
|
||||
" h2 {\n" +
|
||||
" text-align: center;\n" +
|
||||
" margin-bottom: 20px;\n" +
|
||||
" }\n" +
|
||||
" .form-group {\n" +
|
||||
" margin-bottom: 15px;\n" +
|
||||
" }\n" +
|
||||
" label {\n" +
|
||||
" display: block;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" }\n" +
|
||||
" input {\n" +
|
||||
" width: 100%;\n" +
|
||||
" padding: 10px;\n" +
|
||||
" border: 1px solid #ddd;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
" button {\n" +
|
||||
" width: 100%;\n" +
|
||||
" padding: 10px;\n" +
|
||||
" background-color: #007bff;\n" +
|
||||
" color: white;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" }\n" +
|
||||
" button:hover {\n" +
|
||||
" background-color: #0069d9;\n" +
|
||||
" }\n" +
|
||||
" .error-message {\n" +
|
||||
" color: red;\n" +
|
||||
" margin-top: 15px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" display: none;\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"login-container\">\n" +
|
||||
" <h2>用户登录</h2>\n" +
|
||||
" <form id=\"loginForm\">\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"username\">用户名</label>\n" +
|
||||
" <input type=\"text\" id=\"username\" name=\"username\" required>\n" +
|
||||
" </div>\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"password\">密码</label>\n" +
|
||||
" <input type=\"password\" id=\"password\" name=\"password\" required>\n" +
|
||||
" </div>\n" +
|
||||
" <button type=\"submit\">登录</button>\n" +
|
||||
" </form>\n" +
|
||||
" <div id=\"errorMessage\" class=\"error-message\"></div>\n" +
|
||||
" </div>\n" +
|
||||
" <script>\n" +
|
||||
" document.getElementById('loginForm').addEventListener('submit', function(e) {\n" +
|
||||
" e.preventDefault();\n" +
|
||||
" \n" +
|
||||
" const username = document.getElementById('username').value;\n" +
|
||||
" const password = document.getElementById('password').value;\n" +
|
||||
" \n" +
|
||||
" fetch('/oauth2/doLogin?name=' + encodeURIComponent(username) + '&pwd=' + encodeURIComponent(password), {\n" +
|
||||
" method: 'POST'\n" +
|
||||
" })\n" +
|
||||
" .then(response => response.json())\n" +
|
||||
" .then(data => {\n" +
|
||||
" if (data.code === 200) {\n" +
|
||||
" window.location.href = '/oauth2/login-success';\n" +
|
||||
" } else {\n" +
|
||||
" const errorMessage = document.getElementById('errorMessage');\n" +
|
||||
" errorMessage.textContent = data.msg || '登录失败';\n" +
|
||||
" errorMessage.style.display = 'block';\n" +
|
||||
" }\n" +
|
||||
" })\n" +
|
||||
" .catch(error => {\n" +
|
||||
" console.error('登录请求失败:', error);\n" +
|
||||
" const errorMessage = document.getElementById('errorMessage');\n" +
|
||||
" errorMessage.textContent = '网络错误,请稍后重试';\n" +
|
||||
" errorMessage.style.display = 'block';\n" +
|
||||
" });\n" +
|
||||
" });\n" +
|
||||
" </script>\n" +
|
||||
"</body>\n" +
|
||||
"</html>";
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录接口 - 处理表单提交
|
||||
*/
|
||||
@PostMapping("/oauth2/login")
|
||||
@PermitAll
|
||||
public Object login(
|
||||
@RequestParam("username") String username,
|
||||
@RequestParam("password") String password,
|
||||
HttpServletRequest request) {
|
||||
|
||||
// 查询用户
|
||||
SystemUser user = userService.getUserByUsername(username);
|
||||
|
||||
// 验证用户
|
||||
if (user == null || !userService.validatePassword(password, user.getPassword())) {
|
||||
return SaResult.error("账号或密码错误");
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if (user.getStatus() != 0) {
|
||||
return SaResult.error("账号已被禁用");
|
||||
}
|
||||
|
||||
// 登录
|
||||
StpUtil.login(user.getId());
|
||||
|
||||
// 更新登录信息
|
||||
String ip = getClientIp(request);
|
||||
userService.updateLoginInfo(user.getId(), ip);
|
||||
|
||||
// 返回结果
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("tokenValue", StpUtil.getTokenValue());
|
||||
result.put("tokenName", StpUtil.getTokenName());
|
||||
|
||||
return SaResult.data(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录成功页面 - 当未指定回调地址时的默认页面
|
||||
*/
|
||||
@GetMapping("/oauth2/login-success")
|
||||
@PermitAll
|
||||
public Object loginSuccess() {
|
||||
String html = "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"zh-CN\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>授权成功</title>\n" +
|
||||
" <style>\n" +
|
||||
" body {\n" +
|
||||
" font-family: Arial, sans-serif;\n" +
|
||||
" display: flex;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" align-items: center;\n" +
|
||||
" height: 100vh;\n" +
|
||||
" margin: 0;\n" +
|
||||
" background-color: #f5f5f5;\n" +
|
||||
" flex-direction: column;\n" +
|
||||
" }\n" +
|
||||
" .success-container {\n" +
|
||||
" background-color: white;\n" +
|
||||
" padding: 30px;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n" +
|
||||
" width: 400px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" }\n" +
|
||||
" h2 {\n" +
|
||||
" color: #28a745;\n" +
|
||||
" margin-bottom: 20px;\n" +
|
||||
" }\n" +
|
||||
" p {\n" +
|
||||
" margin: 10px 0;\n" +
|
||||
" color: #333;\n" +
|
||||
" }\n" +
|
||||
" .userinfo {\n" +
|
||||
" margin-top: 20px;\n" +
|
||||
" text-align: left;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" background-color: #f8f9fa;\n" +
|
||||
" border-radius: 5px;\n" +
|
||||
" }\n" +
|
||||
" .button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" margin-top: 20px;\n" +
|
||||
" padding: 10px 20px;\n" +
|
||||
" background-color: #007bff;\n" +
|
||||
" color: white;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" }\n" +
|
||||
" .button:hover {\n" +
|
||||
" background-color: #0069d9;\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"success-container\">\n" +
|
||||
" <h2>OAuth2授权成功</h2>\n" +
|
||||
" <p>您已成功登录并授权给应用</p>\n" +
|
||||
" <div class=\"userinfo\">\n" +
|
||||
" <p>当前登录状态:已登录</p>\n" +
|
||||
" <p>令牌信息已生成</p>\n" +
|
||||
" </div>\n" +
|
||||
" <a href=\"javascript:void(0)\" onclick=\"window.close()\" class=\"button\">关闭窗口</a>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>";
|
||||
return html;
|
||||
}
|
||||
}
|
||||
@@ -1,653 +0,0 @@
|
||||
package com.tashow.cloud.controller;
|
||||
import cn.dev33.satoken.sso.config.SaSsoServerConfig;
|
||||
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.dtflys.forest.Forest;
|
||||
import com.tashow.cloud.model.SystemUser;
|
||||
import com.tashow.cloud.service.SystemUserService;
|
||||
import com.tashow.cloud.service.impl.SystemUserServiceImpl;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Sa-Token-SSO Server端 Controller
|
||||
*/
|
||||
@RestController
|
||||
public class SsoServerController {
|
||||
|
||||
@Autowired
|
||||
private SystemUserService userService;
|
||||
|
||||
@Autowired
|
||||
private SystemUserServiceImpl userServiceImpl;
|
||||
|
||||
/**
|
||||
* SSO-Server端:处理所有SSO相关请求 (下面的章节我们会详细列出开放的接口)
|
||||
*/
|
||||
@RequestMapping("/sso/*")
|
||||
@PermitAll
|
||||
public Object ssoRequest() {
|
||||
return SaSsoServerProcessor.instance.dister();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置SSO相关参数
|
||||
*/
|
||||
@Autowired
|
||||
@PermitAll
|
||||
private void configSso(SaSsoServerConfig ssoServer) {
|
||||
// 配置:未登录时返回的View
|
||||
ssoServer.notLoginView = () -> {
|
||||
String msg = "当前会话在SSO-Server端尚未登录,请访问"
|
||||
+ "<a href='/sso/login-page' target='_blank'>登录页面</a>"
|
||||
+ "或 <a href='/sso/register-page' target='_blank'>注册用户</a>"
|
||||
+ ",登录成功后刷新页面开始授权";
|
||||
return msg;
|
||||
};
|
||||
|
||||
// 配置:登录处理函数
|
||||
ssoServer.doLoginHandle = (name, pwd) -> {
|
||||
// 从数据库查询用户
|
||||
SystemUser user = userService.getUserByUsername(name);
|
||||
|
||||
// 验证用户是否存在且密码是否正确
|
||||
if(user != null && userService.validatePassword(pwd, user.getPassword())) {
|
||||
// 用户状态检查
|
||||
if(user.getStatus() != 0) {
|
||||
return SaResult.error("账号已被禁用");
|
||||
}
|
||||
|
||||
// 登录成功,记录用户IP
|
||||
StpUtil.login(user.getId());
|
||||
|
||||
// 获取当前的HTTP请求对象
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
String ip = "unknown";
|
||||
if (attributes != null) {
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
ip = getClientIp(request);
|
||||
}
|
||||
|
||||
userService.updateLoginInfo(user.getId(), ip);
|
||||
|
||||
return SaResult.ok("登录成功!").setData(StpUtil.getTokenValue());
|
||||
}
|
||||
|
||||
return SaResult.error("账号或密码错误");
|
||||
};
|
||||
|
||||
// 配置 Http 请求处理器 (在模式三的单点注销功能下用到,如不需要可以注释掉)
|
||||
ssoServer.sendHttp = url -> {
|
||||
try {
|
||||
System.out.println("------ 发起请求:" + url);
|
||||
String resStr = Forest.get(url).executeAsString();
|
||||
System.out.println("------ 请求结果:" + resStr);
|
||||
return resStr;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端真实IP地址
|
||||
*/
|
||||
private String getClientIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("X-Real-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
// 多个代理的情况,第一个IP为客户端真实IP
|
||||
if (ip != null && ip.indexOf(",") > 0) {
|
||||
ip = ip.substring(0, ip.indexOf(","));
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单点登录检查 - 自定义接口,方便前端调用
|
||||
*/
|
||||
@GetMapping("/sso/checkLogin")
|
||||
@PermitAll
|
||||
public Object ssoCheckLogin() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("isLogin", StpUtil.isLogin());
|
||||
if (StpUtil.isLogin()) {
|
||||
result.put("loginId", StpUtil.getLoginId());
|
||||
result.put("tokenValue", StpUtil.getTokenValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录页面接口 - 返回登录页面HTML
|
||||
*/
|
||||
@GetMapping("/sso/login-page")
|
||||
@PermitAll
|
||||
public Object loginPage() {
|
||||
String html = "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"zh-CN\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>单点登录</title>\n" +
|
||||
" <style>\n" +
|
||||
" body {\n" +
|
||||
" font-family: Arial, sans-serif;\n" +
|
||||
" display: flex;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" align-items: center;\n" +
|
||||
" height: 100vh;\n" +
|
||||
" margin: 0;\n" +
|
||||
" background-color: #f5f5f5;\n" +
|
||||
" }\n" +
|
||||
" .login-container {\n" +
|
||||
" background-color: white;\n" +
|
||||
" padding: 30px;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n" +
|
||||
" width: 350px;\n" +
|
||||
" }\n" +
|
||||
" h2 {\n" +
|
||||
" text-align: center;\n" +
|
||||
" margin-bottom: 20px;\n" +
|
||||
" }\n" +
|
||||
" .form-group {\n" +
|
||||
" margin-bottom: 15px;\n" +
|
||||
" }\n" +
|
||||
" label {\n" +
|
||||
" display: block;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" }\n" +
|
||||
" input {\n" +
|
||||
" width: 100%;\n" +
|
||||
" padding: 10px;\n" +
|
||||
" border: 1px solid #ddd;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
" button {\n" +
|
||||
" width: 100%;\n" +
|
||||
" padding: 10px;\n" +
|
||||
" background-color: #007bff;\n" +
|
||||
" color: white;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" }\n" +
|
||||
" button:hover {\n" +
|
||||
" background-color: #0069d9;\n" +
|
||||
" }\n" +
|
||||
" .error-message {\n" +
|
||||
" color: red;\n" +
|
||||
" margin-top: 15px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" display: none;\n" +
|
||||
" }\n" +
|
||||
" .register-link {\n" +
|
||||
" display: block;\n" +
|
||||
" text-align: center;\n" +
|
||||
" margin-top: 20px;\n" +
|
||||
" color: #28a745;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" }\n" +
|
||||
" .register-link:hover {\n" +
|
||||
" text-decoration: underline;\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"login-container\">\n" +
|
||||
" <h2>用户登录</h2>\n" +
|
||||
" <form id=\"loginForm\">\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"username\">用户名</label>\n" +
|
||||
" <input type=\"text\" id=\"username\" name=\"username\" required>\n" +
|
||||
" </div>\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"password\">密码</label>\n" +
|
||||
" <input type=\"password\" id=\"password\" name=\"password\" required>\n" +
|
||||
" </div>\n" +
|
||||
" <button type=\"submit\">登录</button>\n" +
|
||||
" </form>\n" +
|
||||
" <div id=\"errorMessage\" class=\"error-message\"></div>\n" +
|
||||
" <a href=\"/sso/register-page\" class=\"register-link\">没有账号?点击注册</a>\n" +
|
||||
" </div>\n" +
|
||||
" <script>\n" +
|
||||
" document.getElementById('loginForm').addEventListener('submit', function(e) {\n" +
|
||||
" e.preventDefault();\n" +
|
||||
" \n" +
|
||||
" const username = document.getElementById('username').value;\n" +
|
||||
" const password = document.getElementById('password').value;\n" +
|
||||
" \n" +
|
||||
" fetch('/sso/login', {\n" +
|
||||
" method: 'POST',\n" +
|
||||
" headers: {\n" +
|
||||
" 'Content-Type': 'application/x-www-form-urlencoded',\n" +
|
||||
" },\n" +
|
||||
" body: 'username=' + encodeURIComponent(username) + '&password=' + encodeURIComponent(password)\n" +
|
||||
" })\n" +
|
||||
" .then(response => response.json())\n" +
|
||||
" .then(data => {\n" +
|
||||
" if (data.code === 200) {\n" +
|
||||
" window.location.href = '/sso/login-success';\n" +
|
||||
" } else {\n" +
|
||||
" const errorMessage = document.getElementById('errorMessage');\n" +
|
||||
" errorMessage.textContent = data.msg || '登录失败';\n" +
|
||||
" errorMessage.style.display = 'block';\n" +
|
||||
" }\n" +
|
||||
" })\n" +
|
||||
" .catch(error => {\n" +
|
||||
" console.error('登录请求失败:', error);\n" +
|
||||
" const errorMessage = document.getElementById('errorMessage');\n" +
|
||||
" errorMessage.textContent = '网络错误,请稍后重试';\n" +
|
||||
" errorMessage.style.display = 'block';\n" +
|
||||
" });\n" +
|
||||
" });\n" +
|
||||
" </script>\n" +
|
||||
"</body>\n" +
|
||||
"</html>";
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录接口 - 前端表单登录请求
|
||||
*/
|
||||
@PostMapping("/sso/login")
|
||||
@PermitAll
|
||||
public Object login(
|
||||
@RequestParam("username") String username,
|
||||
@RequestParam("password") String password,
|
||||
HttpServletRequest request) {
|
||||
|
||||
// 查询用户
|
||||
SystemUser user = userService.getUserByUsername(username);
|
||||
|
||||
// 验证用户
|
||||
if (user == null || !userService.validatePassword(password, user.getPassword())) {
|
||||
return SaResult.error("账号或密码错误");
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if (user.getStatus() != 0) {
|
||||
return SaResult.error("账号已被禁用");
|
||||
}
|
||||
|
||||
// 登录
|
||||
StpUtil.login(user.getId());
|
||||
|
||||
// 更新登录信息
|
||||
String ip = getClientIp(request);
|
||||
userService.updateLoginInfo(user.getId(), ip);
|
||||
|
||||
// 返回结果
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("tokenValue", StpUtil.getTokenValue());
|
||||
result.put("tokenName", StpUtil.getTokenName());
|
||||
|
||||
return SaResult.data(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销登录
|
||||
*/
|
||||
@GetMapping("/sso/logout")
|
||||
@PermitAll
|
||||
public Object logout() {
|
||||
if (StpUtil.isLogin()) {
|
||||
StpUtil.logout();
|
||||
return SaResult.ok("注销成功");
|
||||
}
|
||||
return SaResult.error("当前会话未登录");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户信息 - 自定义接口,用于获取当前登录用户信息
|
||||
*/
|
||||
@GetMapping("/sso/userinfo")
|
||||
@PermitAll
|
||||
public Object ssoUserInfo() {
|
||||
if (!StpUtil.isLogin()) {
|
||||
return SaResult.error("用户未登录");
|
||||
}
|
||||
|
||||
Long userId = Long.valueOf(StpUtil.getLoginId().toString());
|
||||
SystemUser user = userService.getUserById(userId);
|
||||
|
||||
if (user == null) {
|
||||
return SaResult.error("用户不存在");
|
||||
}
|
||||
|
||||
// 获取用户角色信息
|
||||
List<String> roleCodes = userServiceImpl.getUserRoleCodes(userId);
|
||||
List<String> roleNames = userServiceImpl.getUserRoleNames(userId);
|
||||
|
||||
Map<String, Object> userInfo = new HashMap<>();
|
||||
userInfo.put("id", user.getId());
|
||||
userInfo.put("username", user.getUsername());
|
||||
userInfo.put("nickname", user.getNickname());
|
||||
userInfo.put("email", user.getEmail());
|
||||
userInfo.put("mobile", user.getMobile());
|
||||
userInfo.put("avatar", user.getAvatar());
|
||||
userInfo.put("roleCodes", roleCodes);
|
||||
userInfo.put("roleNames", roleNames);
|
||||
|
||||
return SaResult.data(userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录成功页面 - 当未指定回调地址时的默认页面
|
||||
*/
|
||||
@GetMapping("/sso/login-success")
|
||||
@PermitAll
|
||||
public Object loginSuccess() {
|
||||
String html = "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"zh-CN\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>登录成功</title>\n" +
|
||||
" <style>\n" +
|
||||
" body {\n" +
|
||||
" font-family: Arial, sans-serif;\n" +
|
||||
" display: flex;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" align-items: center;\n" +
|
||||
" height: 100vh;\n" +
|
||||
" margin: 0;\n" +
|
||||
" background-color: #f5f5f5;\n" +
|
||||
" flex-direction: column;\n" +
|
||||
" }\n" +
|
||||
" .success-container {\n" +
|
||||
" background-color: white;\n" +
|
||||
" padding: 30px;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n" +
|
||||
" width: 400px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" }\n" +
|
||||
" h2 {\n" +
|
||||
" color: #28a745;\n" +
|
||||
" margin-bottom: 20px;\n" +
|
||||
" }\n" +
|
||||
" p {\n" +
|
||||
" margin: 10px 0;\n" +
|
||||
" color: #333;\n" +
|
||||
" }\n" +
|
||||
" .userinfo {\n" +
|
||||
" margin-top: 20px;\n" +
|
||||
" text-align: left;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" background-color: #f8f9fa;\n" +
|
||||
" border-radius: 5px;\n" +
|
||||
" }\n" +
|
||||
" .button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" margin-top: 20px;\n" +
|
||||
" padding: 10px 20px;\n" +
|
||||
" background-color: #007bff;\n" +
|
||||
" color: white;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" }\n" +
|
||||
" .button:hover {\n" +
|
||||
" background-color: #0069d9;\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"success-container\">\n" +
|
||||
" <h2>登录成功</h2>\n" +
|
||||
" <p>您已成功登录到单点登录系统</p>\n" +
|
||||
" <div class=\"userinfo\" id=\"userinfo\">\n" +
|
||||
" <p>正在加载用户信息...</p>\n" +
|
||||
" </div>\n" +
|
||||
" <a href=\"/sso/logout\" class=\"button\">退出登录</a>\n" +
|
||||
" </div>\n" +
|
||||
" <script>\n" +
|
||||
" // 获取用户信息\n" +
|
||||
" fetch('/sso/userinfo')\n" +
|
||||
" .then(response => response.json())\n" +
|
||||
" .then(data => {\n" +
|
||||
" if (data.code === 200 && data.data) {\n" +
|
||||
" const user = data.data;\n" +
|
||||
" let html = '<p><strong>用户ID:</strong>' + user.id + '</p>';\n" +
|
||||
" html += '<p><strong>用户名:</strong>' + user.username + '</p>';\n" +
|
||||
" html += '<p><strong>昵称:</strong>' + user.nickname + '</p>';\n" +
|
||||
" if (user.email) {\n" +
|
||||
" html += '<p><strong>邮箱:</strong>' + user.email + '</p>';\n" +
|
||||
" }\n" +
|
||||
" if (user.mobile) {\n" +
|
||||
" html += '<p><strong>手机:</strong>' + user.mobile + '</p>';\n" +
|
||||
" }\n" +
|
||||
" if (user.roleNames && user.roleNames.length > 0) {\n" +
|
||||
" html += '<p><strong>角色:</strong>' + user.roleNames.join(', ') + '</p>';\n" +
|
||||
" }\n" +
|
||||
" document.getElementById('userinfo').innerHTML = html;\n" +
|
||||
" } else {\n" +
|
||||
" document.getElementById('userinfo').innerHTML = '<p>无法获取用户信息</p>';\n" +
|
||||
" }\n" +
|
||||
" })\n" +
|
||||
" .catch(error => {\n" +
|
||||
" console.error('获取用户信息失败:', error);\n" +
|
||||
" document.getElementById('userinfo').innerHTML = '<p>获取用户信息时发生错误</p>';\n" +
|
||||
" });\n" +
|
||||
" </script>\n" +
|
||||
"</body>\n" +
|
||||
"</html>";
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册页面 - 返回注册页面HTML
|
||||
*/
|
||||
@GetMapping("/sso/register-page")
|
||||
@PermitAll
|
||||
public Object registerPage() {
|
||||
String html = "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"zh-CN\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>用户注册</title>\n" +
|
||||
" <style>\n" +
|
||||
" body {\n" +
|
||||
" font-family: Arial, sans-serif;\n" +
|
||||
" display: flex;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" align-items: center;\n" +
|
||||
" height: 100vh;\n" +
|
||||
" margin: 0;\n" +
|
||||
" background-color: #f5f5f5;\n" +
|
||||
" }\n" +
|
||||
" .register-container {\n" +
|
||||
" background-color: white;\n" +
|
||||
" padding: 30px;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n" +
|
||||
" width: 400px;\n" +
|
||||
" }\n" +
|
||||
" h2 {\n" +
|
||||
" text-align: center;\n" +
|
||||
" margin-bottom: 20px;\n" +
|
||||
" }\n" +
|
||||
" .form-group {\n" +
|
||||
" margin-bottom: 15px;\n" +
|
||||
" }\n" +
|
||||
" label {\n" +
|
||||
" display: block;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" }\n" +
|
||||
" input {\n" +
|
||||
" width: 100%;\n" +
|
||||
" padding: 10px;\n" +
|
||||
" border: 1px solid #ddd;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
" button {\n" +
|
||||
" width: 100%;\n" +
|
||||
" padding: 10px;\n" +
|
||||
" background-color: #28a745;\n" +
|
||||
" color: white;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" }\n" +
|
||||
" button:hover {\n" +
|
||||
" background-color: #218838;\n" +
|
||||
" }\n" +
|
||||
" .error-message {\n" +
|
||||
" color: red;\n" +
|
||||
" margin-top: 15px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" display: none;\n" +
|
||||
" }\n" +
|
||||
" .success-message {\n" +
|
||||
" color: green;\n" +
|
||||
" margin-top: 15px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" display: none;\n" +
|
||||
" }\n" +
|
||||
" .login-link {\n" +
|
||||
" display: block;\n" +
|
||||
" text-align: center;\n" +
|
||||
" margin-top: 20px;\n" +
|
||||
" color: #007bff;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" }\n" +
|
||||
" .login-link:hover {\n" +
|
||||
" text-decoration: underline;\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"register-container\">\n" +
|
||||
" <h2>用户注册</h2>\n" +
|
||||
" <form id=\"registerForm\">\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"username\">用户名 *</label>\n" +
|
||||
" <input type=\"text\" id=\"username\" name=\"username\" required>\n" +
|
||||
" </div>\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"password\">密码 *</label>\n" +
|
||||
" <input type=\"password\" id=\"password\" name=\"password\" required>\n" +
|
||||
" </div>\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"confirmPassword\">确认密码 *</label>\n" +
|
||||
" <input type=\"password\" id=\"confirmPassword\" name=\"confirmPassword\" required>\n" +
|
||||
" </div>\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"nickname\">昵称 *</label>\n" +
|
||||
" <input type=\"text\" id=\"nickname\" name=\"nickname\" required>\n" +
|
||||
" </div>\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"email\">邮箱</label>\n" +
|
||||
" <input type=\"email\" id=\"email\" name=\"email\">\n" +
|
||||
" </div>\n" +
|
||||
" <div class=\"form-group\">\n" +
|
||||
" <label for=\"mobile\">手机号</label>\n" +
|
||||
" <input type=\"tel\" id=\"mobile\" name=\"mobile\">\n" +
|
||||
" </div>\n" +
|
||||
" <button type=\"submit\">注册</button>\n" +
|
||||
" </form>\n" +
|
||||
" <div id=\"errorMessage\" class=\"error-message\"></div>\n" +
|
||||
" <div id=\"successMessage\" class=\"success-message\"></div>\n" +
|
||||
" <a href=\"/sso/login-page\" class=\"login-link\">已有账号?点击登录</a>\n" +
|
||||
" </div>\n" +
|
||||
" <script>\n" +
|
||||
" document.getElementById('registerForm').addEventListener('submit', function(e) {\n" +
|
||||
" e.preventDefault();\n" +
|
||||
" \n" +
|
||||
" const username = document.getElementById('username').value;\n" +
|
||||
" const password = document.getElementById('password').value;\n" +
|
||||
" const confirmPassword = document.getElementById('confirmPassword').value;\n" +
|
||||
" const nickname = document.getElementById('nickname').value;\n" +
|
||||
" const email = document.getElementById('email').value;\n" +
|
||||
" const mobile = document.getElementById('mobile').value;\n" +
|
||||
" \n" +
|
||||
" // 简单前端验证\n" +
|
||||
" if (password !== confirmPassword) {\n" +
|
||||
" const errorMessage = document.getElementById('errorMessage');\n" +
|
||||
" errorMessage.textContent = '两次输入的密码不一致';\n" +
|
||||
" errorMessage.style.display = 'block';\n" +
|
||||
" return;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" // 构建表单数据\n" +
|
||||
" const formData = new URLSearchParams();\n" +
|
||||
" formData.append('username', username);\n" +
|
||||
" formData.append('password', password);\n" +
|
||||
" formData.append('nickname', nickname);\n" +
|
||||
" if (email) formData.append('email', email);\n" +
|
||||
" if (mobile) formData.append('mobile', mobile);\n" +
|
||||
" \n" +
|
||||
" // 发送注册请求\n" +
|
||||
" fetch('/user/register', {\n" +
|
||||
" method: 'POST',\n" +
|
||||
" headers: {\n" +
|
||||
" 'Content-Type': 'application/x-www-form-urlencoded',\n" +
|
||||
" },\n" +
|
||||
" body: formData\n" +
|
||||
" })\n" +
|
||||
" .then(response => response.json())\n" +
|
||||
" .then(data => {\n" +
|
||||
" if (data.code === 200) {\n" +
|
||||
" const successMessage = document.getElementById('successMessage');\n" +
|
||||
" successMessage.textContent = '注册成功!3秒后跳转到登录页面...';\n" +
|
||||
" successMessage.style.display = 'block';\n" +
|
||||
" \n" +
|
||||
" // 清空表单\n" +
|
||||
" document.getElementById('registerForm').reset();\n" +
|
||||
" \n" +
|
||||
" // 3秒后跳转到登录页面\n" +
|
||||
" setTimeout(() => {\n" +
|
||||
" window.location.href = '/sso/login-page';\n" +
|
||||
" }, 3000);\n" +
|
||||
" } else {\n" +
|
||||
" const errorMessage = document.getElementById('errorMessage');\n" +
|
||||
" errorMessage.textContent = data.msg || '注册失败,请稍后重试';\n" +
|
||||
" errorMessage.style.display = 'block';\n" +
|
||||
" }\n" +
|
||||
" })\n" +
|
||||
" .catch(error => {\n" +
|
||||
" console.error('注册请求失败:', error);\n" +
|
||||
" const errorMessage = document.getElementById('errorMessage');\n" +
|
||||
" errorMessage.textContent = '网络错误,请稍后重试';\n" +
|
||||
" errorMessage.style.display = 'block';\n" +
|
||||
" });\n" +
|
||||
" });\n" +
|
||||
" </script>\n" +
|
||||
"</body>\n" +
|
||||
"</html>";
|
||||
return html;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.tashow.cloud.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统角色实体类
|
||||
*/
|
||||
@Data
|
||||
@TableName("system_role")
|
||||
public class SystemRole {
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 角色权限字符串
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)
|
||||
*/
|
||||
private Integer dataScope;
|
||||
|
||||
/**
|
||||
* 数据范围(指定部门数组)
|
||||
*/
|
||||
private String dataScopeDeptIds;
|
||||
|
||||
/**
|
||||
* 角色状态(0正常 1停用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 角色类型
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package com.tashow.cloud.service;
|
||||
|
||||
import com.tashow.cloud.model.SystemUser;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统用户服务接口
|
||||
*/
|
||||
public interface SystemUserService {
|
||||
|
||||
/**
|
||||
* 根据用户名查询用户
|
||||
*
|
||||
* @param username 用户名
|
||||
* @return 用户信息
|
||||
*/
|
||||
SystemUser getUserByUsername(String username);
|
||||
|
||||
/**
|
||||
* 验证用户密码
|
||||
*
|
||||
* @param rawPassword 原始密码
|
||||
* @param encodedPassword 编码后的密码
|
||||
* @return 是否匹配
|
||||
*/
|
||||
boolean validatePassword(String rawPassword, String encodedPassword);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取用户信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户信息
|
||||
*/
|
||||
SystemUser getUserById(Long userId);
|
||||
|
||||
/**
|
||||
* 更新用户登录信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param ip 登录IP
|
||||
*/
|
||||
void updateLoginInfo(Long userId, String ip);
|
||||
|
||||
/**
|
||||
* 注册新用户
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @return 是否注册成功
|
||||
*/
|
||||
boolean registerUser(SystemUser user);
|
||||
|
||||
/**
|
||||
* 加密密码
|
||||
*
|
||||
* @param rawPassword 原始密码
|
||||
* @return 加密后的密码
|
||||
*/
|
||||
String encodePassword(String rawPassword);
|
||||
|
||||
/**
|
||||
* 获取用户角色ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色ID列表
|
||||
*/
|
||||
List<Long> getUserRoleIds(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户角色名称列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色名称列表
|
||||
*/
|
||||
List<String> getUserRoleNames(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户角色编码列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色编码列表
|
||||
*/
|
||||
List<String> getUserRoleCodes(Long userId);
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
package com.tashow.cloud.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.tashow.cloud.mapper.SystemUserMapper;
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import com.tashow.cloud.model.SystemUser;
|
||||
import com.tashow.cloud.model.SystemUserRole;
|
||||
import com.tashow.cloud.service.SystemRoleService;
|
||||
import com.tashow.cloud.service.SystemUserRoleService;
|
||||
import com.tashow.cloud.service.SystemUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 系统用户服务实现类
|
||||
*/
|
||||
@Service
|
||||
public class SystemUserServiceImpl extends ServiceImpl<SystemUserMapper, SystemUser> implements SystemUserService {
|
||||
|
||||
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
|
||||
@Autowired
|
||||
private SystemRoleService systemRoleService;
|
||||
|
||||
@Autowired
|
||||
private SystemUserRoleService systemUserRoleService;
|
||||
|
||||
@Override
|
||||
public SystemUser getUserByUsername(String username) {
|
||||
return getOne(new LambdaQueryWrapper<SystemUser>()
|
||||
.eq(SystemUser::getUsername, username)
|
||||
.eq(SystemUser::getStatus, 0)
|
||||
.eq(SystemUser::getDeleted, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validatePassword(String rawPassword, String encodedPassword) {
|
||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemUser getUserById(Long userId) {
|
||||
return getOne(new LambdaQueryWrapper<SystemUser>()
|
||||
.eq(SystemUser::getId, userId)
|
||||
.eq(SystemUser::getDeleted, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLoginInfo(Long userId, String ip) {
|
||||
SystemUser user = new SystemUser();
|
||||
user.setId(userId);
|
||||
user.setLoginIp(ip);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
user.setLoginDate(now);
|
||||
user.setUpdateTime(now);
|
||||
updateById(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerUser(SystemUser user) {
|
||||
// 设置默认值
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
user.setCreateTime(now);
|
||||
user.setUpdateTime(now);
|
||||
user.setLoginDate(now);
|
||||
user.setCreator("system");
|
||||
user.setUpdater("system");
|
||||
|
||||
if (user.getAvatar() == null || user.getAvatar().isEmpty()) {
|
||||
user.setAvatar("https://sa-token.cc/logo.png"); // 设置默认头像
|
||||
}
|
||||
|
||||
user.setTenantId(0L); // 默认租户ID
|
||||
user.setDeleted(false); // 设置为未删除
|
||||
|
||||
return save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodePassword(String rawPassword) {
|
||||
return passwordEncoder.encode(rawPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户角色ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色ID列表
|
||||
*/
|
||||
@Override
|
||||
public List<Long> getUserRoleIds(Long userId) {
|
||||
List<SystemUserRole> userRoles = systemUserRoleService.list(new LambdaQueryWrapper<SystemUserRole>()
|
||||
.eq(SystemUserRole::getUserId, userId)
|
||||
.eq(SystemUserRole::getDeleted, false));
|
||||
|
||||
return userRoles.stream()
|
||||
.map(SystemUserRole::getRoleId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户角色名称列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色名称列表
|
||||
*/
|
||||
@Override
|
||||
public List<String> getUserRoleNames(Long userId) {
|
||||
// 先获取用户角色ID列表
|
||||
List<Long> roleIds = getUserRoleIds(userId);
|
||||
if (roleIds.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 再查询角色名称
|
||||
List<SystemRole> roles = systemRoleService.list(new LambdaQueryWrapper<SystemRole>()
|
||||
.in(SystemRole::getId, roleIds)
|
||||
.eq(SystemRole::getStatus, 0)
|
||||
.eq(SystemRole::getDeleted, false));
|
||||
|
||||
return roles.stream()
|
||||
.map(SystemRole::getName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户角色编码列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色编码列表
|
||||
*/
|
||||
@Override
|
||||
public List<String> getUserRoleCodes(Long userId) {
|
||||
// 先获取用户角色ID列表
|
||||
List<Long> roleIds = getUserRoleIds(userId);
|
||||
if (roleIds.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 再查询角色编码
|
||||
List<SystemRole> roles = systemRoleService.list(new LambdaQueryWrapper<SystemRole>()
|
||||
.in(SystemRole::getId, roleIds)
|
||||
.eq(SystemRole::getStatus, 0)
|
||||
.eq(SystemRole::getDeleted, false));
|
||||
|
||||
return roles.stream()
|
||||
.map(SystemRole::getCode)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.tashow.cloud.config;
|
||||
package com.tashow.cloud.sso.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.tashow.cloud.sso.controller;
|
||||
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
|
||||
import cn.dev33.satoken.sso.template.SaSsoUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.tashow.cloud.sso.model.SystemUser;
|
||||
import com.tashow.cloud.sso.service.SystemUserService;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
/**
|
||||
* Sa-Token-SSO Server端 Controller
|
||||
*/
|
||||
@RestController
|
||||
public class SsoServerController {
|
||||
@Autowired
|
||||
private SystemUserService systemUserService;
|
||||
/**
|
||||
* SSO-Server端:处理所有SSO相关请求 (下面的章节我们会详细列出开放的接口)
|
||||
*/
|
||||
@RequestMapping("sso/*")
|
||||
@PermitAll
|
||||
public Object ssoRequest() {
|
||||
return SaSsoServerProcessor.instance.dister();
|
||||
}
|
||||
|
||||
// 测试登录,浏览器访问: http://localhost:48083/doLogin?username=zhang&password=123456
|
||||
@RequestMapping("doLogin")
|
||||
@PermitAll
|
||||
public String doLogin(String username, String password) {
|
||||
// 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对
|
||||
if("zhang".equals(username) && "123456".equals(password)) {
|
||||
StpUtil.login(10001);
|
||||
return "登录成功";
|
||||
}
|
||||
return "登录失败";
|
||||
}
|
||||
// 返回SSO认证中心登录地址
|
||||
@PermitAll
|
||||
@RequestMapping("sso/getSsoAuthUrl")
|
||||
public SaResult getSsoAuthUrl(String clientLoginUrl) {
|
||||
String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, "");
|
||||
return SaResult.data(serverAuthUrl);
|
||||
}
|
||||
|
||||
|
||||
// 查询登录状态,浏览器访问: http://localhost:48083/isLogin
|
||||
@RequestMapping("isLogin")
|
||||
@PermitAll
|
||||
public String isLogin() {
|
||||
return "当前会话是否登录:" + StpUtil.isLogin();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
package com.tashow.cloud.framework.core;
|
||||
|
||||
package com.tashow.cloud.sso.framework.core;
|
||||
import com.xingyuv.captcha.service.CaptchaCacheService;
|
||||
import lombok.Setter;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
@@ -21,6 +20,7 @@ public class RedisCaptchaServiceImpl implements CaptchaCacheService {
|
||||
return "redis";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set(String key, String value, long expiresInSeconds) {
|
||||
stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.tashow.cloud.mapper;
|
||||
package com.tashow.cloud.sso.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import com.tashow.cloud.sso.model.SystemRole;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 系统角色Mapper接口
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.tashow.cloud.mapper;
|
||||
package com.tashow.cloud.sso.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tashow.cloud.model.SystemUser;
|
||||
import com.tashow.cloud.sso.model.SystemUser;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.tashow.cloud.mapper;
|
||||
package com.tashow.cloud.sso.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tashow.cloud.model.SystemUserRole;
|
||||
import com.tashow.cloud.sso.model.SystemUserRole;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.tashow.cloud.model;
|
||||
package com.tashow.cloud.sso.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.tashow.cloud.model;
|
||||
package com.tashow.cloud.sso.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -7,6 +8,7 @@ import java.time.LocalDateTime;
|
||||
* 系统用户实体类
|
||||
*/
|
||||
@Data
|
||||
@TableName("system_users")
|
||||
public class SystemUser {
|
||||
/**
|
||||
* 用户ID
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.tashow.cloud.model;
|
||||
package com.tashow.cloud.sso.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.tashow.cloud.security.config;
|
||||
package com.tashow.cloud.sso.security.config;
|
||||
|
||||
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.tashow.cloud.security.config;
|
||||
package com.tashow.cloud.sso.security.config;
|
||||
|
||||
import com.tashow.cloud.security.security.config.AuthorizeRequestsCustomizer;
|
||||
import com.tashow.cloud.systemapi.enums.ApiConstants;
|
||||
@@ -25,6 +25,8 @@ public class SecurityConfiguration {
|
||||
.requestMatchers("/webjars/**").permitAll()
|
||||
.requestMatchers("/swagger-ui").permitAll()
|
||||
.requestMatchers("/swagger-ui/**").permitAll()
|
||||
.requestMatchers("/oauth2/**").permitAll()
|
||||
.requestMatchers("/sso/**").permitAll()
|
||||
;
|
||||
// Druid 监控
|
||||
registry.requestMatchers("/druid/**").permitAll();
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.tashow.cloud.service;
|
||||
package com.tashow.cloud.sso.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import com.tashow.cloud.sso.model.SystemRole;
|
||||
|
||||
/**
|
||||
* 系统角色服务接口
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.tashow.cloud.service;
|
||||
package com.tashow.cloud.sso.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.tashow.cloud.model.SystemUserRole;
|
||||
import com.tashow.cloud.sso.model.SystemUserRole;
|
||||
|
||||
/**
|
||||
* 系统用户角色关联服务接口
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.tashow.cloud.sso.service;
|
||||
|
||||
import com.tashow.cloud.sso.model.SystemUser;
|
||||
|
||||
/**
|
||||
* 系统用户服务接口
|
||||
*/
|
||||
public interface SystemUserService {
|
||||
|
||||
/**
|
||||
* 根据用户名查询用户
|
||||
*
|
||||
* @param username 用户名
|
||||
* @return 用户信息
|
||||
*/
|
||||
SystemUser getUserByUsername(String username);
|
||||
|
||||
/**
|
||||
* 验证用户密码
|
||||
*
|
||||
* @param rawPassword 原始密码
|
||||
* @param encodedPassword 编码后的密码
|
||||
* @return 是否匹配
|
||||
*/
|
||||
boolean validatePassword(String rawPassword, String encodedPassword);
|
||||
|
||||
|
||||
/**
|
||||
* 更新用户登录信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param ip 登录IP
|
||||
*/
|
||||
void updateLoginInfo(Long userId, String ip);
|
||||
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.tashow.cloud.service.impl;
|
||||
package com.tashow.cloud.sso.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.tashow.cloud.mapper.SystemRoleMapper;
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import com.tashow.cloud.service.SystemRoleService;
|
||||
import com.tashow.cloud.sso.mapper.SystemRoleMapper;
|
||||
import com.tashow.cloud.sso.model.SystemRole;
|
||||
import com.tashow.cloud.sso.service.SystemRoleService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.tashow.cloud.service.impl;
|
||||
package com.tashow.cloud.sso.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.tashow.cloud.mapper.SystemUserRoleMapper;
|
||||
import com.tashow.cloud.model.SystemUserRole;
|
||||
import com.tashow.cloud.service.SystemUserRoleService;
|
||||
import com.tashow.cloud.sso.mapper.SystemUserRoleMapper;
|
||||
import com.tashow.cloud.sso.model.SystemUserRole;
|
||||
import com.tashow.cloud.sso.service.SystemUserRoleService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.tashow.cloud.sso.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.tashow.cloud.sso.mapper.SystemUserMapper;
|
||||
import com.tashow.cloud.sso.model.SystemUser;
|
||||
import com.tashow.cloud.sso.service.SystemUserService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统用户服务实现类
|
||||
*/
|
||||
@Service
|
||||
public class SystemUserServiceImpl extends ServiceImpl<SystemUserMapper, SystemUser> implements SystemUserService {
|
||||
|
||||
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
|
||||
|
||||
@Override
|
||||
public SystemUser getUserByUsername(String username) {
|
||||
return getOne(new LambdaQueryWrapper<SystemUser>()
|
||||
.eq(SystemUser::getUsername, username)
|
||||
.eq(SystemUser::getStatus, 0)
|
||||
.eq(SystemUser::getDeleted, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validatePassword(String rawPassword, String encodedPassword) {
|
||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateLoginInfo(Long userId, String ip) {
|
||||
SystemUser user = new SystemUser();
|
||||
user.setId(userId);
|
||||
user.setLoginIp(ip);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
user.setLoginDate(now);
|
||||
user.setUpdateTime(now);
|
||||
updateById(user);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
com.tashow.cloud.framework.core.RedisCaptchaServiceImpl
|
||||
com.tashow.cloud.sso.framework.core.RedisCaptchaServiceImpl
|
||||
@@ -137,7 +137,7 @@ aj:
|
||||
tashow:
|
||||
info:
|
||||
version: 1.0.0
|
||||
base-package: com.tashow.cloud.system
|
||||
base-package: com.tashow.cloud
|
||||
web:
|
||||
admin-ui:
|
||||
url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址
|
||||
@@ -161,6 +161,8 @@ tashow:
|
||||
- /rpc-api/system/tenant/valid # 防止递归。避免调用 /rpc-api/system/tenant/valid 接口时,又去触发 /rpc-api/system/tenant/valid 去校验
|
||||
- /rpc-api/system/tenant/id-list # 获得租户列表的时候,无需传递租户编号
|
||||
- /rpc-api/system/oauth2/token/check # 访问令牌校验时,无需传递租户编号;主要解决上传文件的场景,前端不会传递 tenant-id!
|
||||
# - /oauth2/* # OAuth2相关接口,无需传递租户编号
|
||||
# - /oauth2/login # OAuth2登录接口,无需传递租户编号
|
||||
ignore-tables:
|
||||
- system_tenant
|
||||
- system_tenant_package
|
||||
@@ -196,21 +198,20 @@ debug: false
|
||||
|
||||
|
||||
sa-token:
|
||||
# ------- SSO-模式一相关配置 (非模式一不需要配置)
|
||||
# cookie:
|
||||
# 配置 Cookie 作用域
|
||||
# domain: stp.com
|
||||
|
||||
# ------- SSO-模式二相关配置
|
||||
sso-server:
|
||||
# Ticket有效期 (单位: 秒),默认五分钟
|
||||
ticket-timeout: 300
|
||||
# 所有允许的授权回调地址
|
||||
allow-url: "*"
|
||||
home-route: "/sso/login-success"
|
||||
# ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
|
||||
# 是否打开模式三
|
||||
is-http: true
|
||||
# token 名称(同时也是 cookie 名称)
|
||||
token-name: token
|
||||
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
|
||||
timeout: 2592000
|
||||
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
|
||||
active-timeout: -1
|
||||
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
|
||||
is-share: false
|
||||
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
|
||||
token-style: uuid
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
|
||||
# OAuth2相关配置
|
||||
oauth2:
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package com.tashow.cloud.system.api.logger;
|
||||
|
||||
import com.tashow.cloud.common.pojo.CommonResult;
|
||||
import com.tashow.cloud.systemapi.api.logger.LoginLogApi;
|
||||
import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO;
|
||||
import com.tashow.cloud.system.service.logger.LoginLogService;
|
||||
import com.tashow.cloud.systemapi.api.logger.dto.LoginLogCreateReqDTO;
|
||||
import com.tashow.cloud.system.service.logger.LoginLogService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-module</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<modules>
|
||||
<module>tashow-module-user-api</module>
|
||||
<module>tashow-module-user-biz</module>
|
||||
</modules>
|
||||
<artifactId>tashow-module-user</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
system 模块下,我们放通用业务,支撑上层的核心业务。
|
||||
例如说:用户、部门、权限、数据字典等等
|
||||
</description>
|
||||
|
||||
</project>
|
||||
@@ -1,10 +0,0 @@
|
||||
# Getting Started
|
||||
|
||||
### Reference Documentation
|
||||
|
||||
For further reference, please consider the following sections:
|
||||
|
||||
* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
|
||||
* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/)
|
||||
* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/#build-image)
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-module-user</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>tashow-module-user-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
system 模块 API,暴露给其它模块调用
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId> <!-- 接口文档:使用最新版本的 Swagger 模型 -->
|
||||
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-annotation</artifactId>
|
||||
<version>3.5.9</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,63 +0,0 @@
|
||||
package com.tashow.cloud.convert;
|
||||
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 系统角色对象转换器
|
||||
*/
|
||||
@Mapper
|
||||
public interface SystemRoleConvert {
|
||||
|
||||
SystemRoleConvert INSTANCE = Mappers.getMapper(SystemRoleConvert.class);
|
||||
|
||||
/**
|
||||
* 将角色列表转换为角色ID列表
|
||||
*
|
||||
* @param roles 角色列表
|
||||
* @return 角色ID列表
|
||||
*/
|
||||
default List<Long> convertToRoleIds(List<SystemRole> roles) {
|
||||
if (roles == null || roles.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return roles.stream()
|
||||
.map(SystemRole::getId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将角色列表转换为角色名称列表
|
||||
*
|
||||
* @param roles 角色列表
|
||||
* @return 角色名称列表
|
||||
*/
|
||||
default List<String> convertToRoleNames(List<SystemRole> roles) {
|
||||
if (roles == null || roles.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return roles.stream()
|
||||
.map(SystemRole::getName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将角色列表转换为角色编码列表
|
||||
*
|
||||
* @param roles 角色列表
|
||||
* @return 角色编码列表
|
||||
*/
|
||||
default List<String> convertToRoleCodes(List<SystemRole> roles) {
|
||||
if (roles == null || roles.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return roles.stream()
|
||||
.map(SystemRole::getCode)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.tashow.cloud.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 角色菜单关联实体类
|
||||
*/
|
||||
@Data
|
||||
@TableName("system_role_menu")
|
||||
public class SystemRoleMenu {
|
||||
/**
|
||||
* 自增编号
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 菜单ID
|
||||
*/
|
||||
private Long menuId;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package com.tashow.cloud.model;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统用户实体类
|
||||
*/
|
||||
@Data
|
||||
@TableName("system_users")
|
||||
public class SystemUser {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 岗位编号数组
|
||||
*/
|
||||
private String postIds;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 帐号状态(0正常 1停用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
private LocalDateTime loginDate;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.tashow.cloud.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 用户岗位关联实体类
|
||||
*/
|
||||
@Data
|
||||
@TableName("system_user_post")
|
||||
public class SystemUserPost {
|
||||
/**
|
||||
* 自增编号
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 岗位ID
|
||||
*/
|
||||
private Long postId;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.tashow.cloud.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 用户角色关联实体类
|
||||
*/
|
||||
@Data
|
||||
@TableName("system_user_role")
|
||||
public class SystemUserRole {
|
||||
/**
|
||||
* 自增编号
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.tashow.cloud.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户注册请求DTO
|
||||
*/
|
||||
@Data
|
||||
public class UserRegisterReqDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
@NotEmpty(message = "用户账号不能为空")
|
||||
@Size(min = 4, max = 16, message = "账号长度为 4-16 位")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@NotEmpty(message = "密码不能为空")
|
||||
@Size(min = 4, max = 16, message = "密码长度为 4-16 位")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
@Size(max = 30, message = "用户昵称长度不能超过30个字符")
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
@Email(message = "邮箱格式不正确")
|
||||
@Size(max = 50, message = "邮箱长度不能超过50个字符")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号码格式不正确")
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
/**
|
||||
* 登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.tashow.cloud.service;
|
||||
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统角色服务接口
|
||||
*/
|
||||
public interface SystemRoleService {
|
||||
|
||||
/**
|
||||
* 创建角色
|
||||
*
|
||||
* @param role 角色信息
|
||||
* @param menuIds 菜单ID列表
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
boolean createRole(SystemRole role, List<Long> menuIds);
|
||||
|
||||
/**
|
||||
* 更新角色
|
||||
*
|
||||
* @param role 角色信息
|
||||
* @param menuIds 菜单ID列表
|
||||
* @return 是否更新成功
|
||||
*/
|
||||
boolean updateRole(SystemRole role, List<Long> menuIds);
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
boolean deleteRole(Long roleId);
|
||||
|
||||
/**
|
||||
* 获取角色信息
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 角色信息
|
||||
*/
|
||||
SystemRole getRoleById(Long roleId);
|
||||
|
||||
/**
|
||||
* 根据角色编码获取角色
|
||||
*
|
||||
* @param code 角色编码
|
||||
* @return 角色信息
|
||||
*/
|
||||
SystemRole getRoleByCode(String code);
|
||||
|
||||
/**
|
||||
* 获取所有角色列表
|
||||
*
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<SystemRole> getAllRoles();
|
||||
|
||||
/**
|
||||
* 获取指定状态的角色列表
|
||||
*
|
||||
* @param status 状态
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<SystemRole> getRolesByStatus(Integer status);
|
||||
|
||||
/**
|
||||
* 获取角色的菜单ID列表
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 菜单ID列表
|
||||
*/
|
||||
List<Long> getRoleMenuIds(Long roleId);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取角色列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<SystemRole> getRolesByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 更新角色状态
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @param status 新状态
|
||||
* @return 是否更新成功
|
||||
*/
|
||||
boolean updateRoleStatus(Long roleId, Integer status);
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package com.tashow.cloud.service;
|
||||
|
||||
import com.tashow.cloud.model.SystemUser;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统用户服务接口
|
||||
*/
|
||||
public interface SystemUserService {
|
||||
|
||||
/**
|
||||
* 根据用户名查询用户
|
||||
*
|
||||
* @param username 用户名
|
||||
* @return 用户信息
|
||||
*/
|
||||
SystemUser getUserByUsername(String username);
|
||||
|
||||
/**
|
||||
* 验证用户密码
|
||||
*
|
||||
* @param rawPassword 原始密码
|
||||
* @param encodedPassword 编码后的密码
|
||||
* @return 是否匹配
|
||||
*/
|
||||
boolean validatePassword(String rawPassword, String encodedPassword);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取用户信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户信息
|
||||
*/
|
||||
SystemUser getUserById(Long userId);
|
||||
|
||||
/**
|
||||
* 更新用户登录信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param ip 登录IP
|
||||
*/
|
||||
void updateLoginInfo(Long userId, String ip);
|
||||
|
||||
/**
|
||||
* 注册新用户
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @return 是否注册成功
|
||||
*/
|
||||
boolean registerUser(SystemUser user);
|
||||
|
||||
/**
|
||||
* 加密密码
|
||||
*
|
||||
* @param rawPassword 原始密码
|
||||
* @return 加密后的密码
|
||||
*/
|
||||
String encodePassword(String rawPassword);
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @param roleIds 角色ID列表
|
||||
* @param postIds 岗位ID列表
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
boolean createUser(SystemUser user, List<Long> roleIds, List<Long> postIds);
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @param roleIds 角色ID列表
|
||||
* @param postIds 岗位ID列表
|
||||
* @return 是否更新成功
|
||||
*/
|
||||
boolean updateUser(SystemUser user, List<Long> roleIds, List<Long> postIds);
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
boolean deleteUser(Long userId);
|
||||
|
||||
/**
|
||||
* 重置用户密码
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param newPassword 新密码
|
||||
* @return 是否重置成功
|
||||
*/
|
||||
boolean resetUserPassword(Long userId, String newPassword);
|
||||
|
||||
/**
|
||||
* 更新用户状态
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param status 新状态
|
||||
* @return 是否更新成功
|
||||
*/
|
||||
boolean updateUserStatus(Long userId, Integer status);
|
||||
|
||||
/**
|
||||
* 获取用户角色ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色ID列表
|
||||
*/
|
||||
List<Long> getUserRoleIds(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户角色名称列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色名称列表
|
||||
*/
|
||||
List<String> getUserRoleNames(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户角色编码列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色编码列表
|
||||
*/
|
||||
List<String> getUserRoleCodes(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户岗位ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 岗位ID列表
|
||||
*/
|
||||
List<Long> getUserPostIds(Long userId);
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.tashow.cloud.user.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户创建请求DTO
|
||||
*/
|
||||
@Data
|
||||
public class UserCreateReqDTO {
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 角色ID列表
|
||||
*/
|
||||
private List<Long> roleIds;
|
||||
|
||||
/**
|
||||
* 岗位ID列表
|
||||
*/
|
||||
private List<Long> postIds;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.tashow.cloud.user.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户分页查询请求DTO
|
||||
*/
|
||||
@Data
|
||||
public class UserPageReqDTO {
|
||||
|
||||
/**
|
||||
* 当前页码
|
||||
*/
|
||||
private Integer pageNum = 1;
|
||||
|
||||
/**
|
||||
* 每页条数
|
||||
*/
|
||||
private Integer pageSize = 10;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 帐号状态(0正常 1停用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 开始创建时间
|
||||
*/
|
||||
private String beginCreateTime;
|
||||
|
||||
/**
|
||||
* 结束创建时间
|
||||
*/
|
||||
private String endCreateTime;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.tashow.cloud.user.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户注册请求DTO
|
||||
*/
|
||||
@Data
|
||||
public class UserRegisterReqDTO {
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package com.tashow.cloud.user.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户响应DTO
|
||||
*/
|
||||
@Data
|
||||
public class UserRespDTO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
/**
|
||||
* 性别名称
|
||||
*/
|
||||
private String sexName;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 帐号状态(0正常 1停用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 状态名称
|
||||
*/
|
||||
private String statusName;
|
||||
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
private LocalDateTime loginDate;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 角色ID列表
|
||||
*/
|
||||
private List<Long> roleIds;
|
||||
|
||||
/**
|
||||
* 角色名称列表
|
||||
*/
|
||||
private List<String> roleNames;
|
||||
|
||||
/**
|
||||
* 角色编码列表
|
||||
*/
|
||||
private List<String> roleCodes;
|
||||
|
||||
/**
|
||||
* 岗位ID列表
|
||||
*/
|
||||
private List<Long> postIds;
|
||||
|
||||
/**
|
||||
* 岗位名称列表
|
||||
*/
|
||||
private List<String> postNames;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.tashow.cloud.user.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户更新请求DTO
|
||||
*/
|
||||
@Data
|
||||
public class UserUpdateReqDTO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 帐号状态(0正常 1停用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 角色ID列表
|
||||
*/
|
||||
private List<Long> roleIds;
|
||||
|
||||
/**
|
||||
* 岗位ID列表
|
||||
*/
|
||||
private List<Long> postIds;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.tashow.cloud.user.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 基础实体类,包含所有实体共有的字段
|
||||
*/
|
||||
@Data
|
||||
public class BaseEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.tashow.cloud.user.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 角色信息实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("system_role")
|
||||
public class Role extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 角色权限字符串
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)
|
||||
*/
|
||||
private Integer dataScope;
|
||||
|
||||
/**
|
||||
* 数据范围(指定部门数组)
|
||||
*/
|
||||
private String dataScopeDeptIds;
|
||||
|
||||
/**
|
||||
* 角色状态(0正常 1停用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 角色类型
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.tashow.cloud.user.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 角色菜单关联实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("system_role_menu")
|
||||
public class RoleMenu extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 自增编号
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 菜单ID
|
||||
*/
|
||||
private Long menuId;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package com.tashow.cloud.user.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户信息实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("system_users")
|
||||
public class User extends BaseEntity {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 岗位编号数组
|
||||
*/
|
||||
private String postIds;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 用户性别
|
||||
* 0: 未知
|
||||
* 1: 男
|
||||
* 2: 女
|
||||
*/
|
||||
private Integer sex;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 帐号状态
|
||||
* 0: 正常
|
||||
* 1: 停用
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
private java.time.LocalDateTime loginDate;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 角色列表 - 非数据库字段
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<Role> roles;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.tashow.cloud.user.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户岗位关联实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("system_user_post")
|
||||
public class UserPost extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 自增编号
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 岗位ID
|
||||
*/
|
||||
private Long postId;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.tashow.cloud.user.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户角色关联实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("system_user_role")
|
||||
public class UserRole extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 自增编号
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package com.tashow.cloud.user.service;
|
||||
|
||||
import com.tashow.cloud.user.model.Role;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色服务接口
|
||||
*/
|
||||
public interface RoleService {
|
||||
|
||||
/**
|
||||
* 创建角色
|
||||
*
|
||||
* @param role 角色信息
|
||||
* @param menuIds 菜单ID列表
|
||||
* @return 角色ID
|
||||
*/
|
||||
Long createRole(Role role, List<Long> menuIds);
|
||||
|
||||
/**
|
||||
* 更新角色
|
||||
*
|
||||
* @param role 角色信息
|
||||
* @param menuIds 菜单ID列表
|
||||
*/
|
||||
void updateRole(Role role, List<Long> menuIds);
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
void deleteRole(Long roleId);
|
||||
|
||||
/**
|
||||
* 获取角色信息
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 角色信息
|
||||
*/
|
||||
Role getRoleById(Long roleId);
|
||||
|
||||
/**
|
||||
* 根据角色编码获取角色
|
||||
*
|
||||
* @param code 角色编码
|
||||
* @return 角色信息
|
||||
*/
|
||||
Role getRoleByCode(String code);
|
||||
|
||||
/**
|
||||
* 获取所有角色列表
|
||||
*
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<Role> getAllRoles();
|
||||
|
||||
/**
|
||||
* 获取指定状态的角色列表
|
||||
*
|
||||
* @param status 状态
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<Role> getRolesByStatus(Integer status);
|
||||
|
||||
/**
|
||||
* 获取角色的菜单ID列表
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 菜单ID列表
|
||||
*/
|
||||
List<Long> getRoleMenuIds(Long roleId);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取角色列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<Role> getRolesByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 更新角色状态
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @param status 新状态
|
||||
*/
|
||||
void updateRoleStatus(Long roleId, Integer status);
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package com.tashow.cloud.user.service;
|
||||
|
||||
import com.tashow.cloud.user.dto.UserCreateReqDTO;
|
||||
import com.tashow.cloud.user.dto.UserPageReqDTO;
|
||||
import com.tashow.cloud.user.dto.UserRegisterReqDTO;
|
||||
import com.tashow.cloud.user.dto.UserRespDTO;
|
||||
import com.tashow.cloud.user.dto.UserUpdateReqDTO;
|
||||
import com.tashow.cloud.user.model.User;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户服务接口
|
||||
*/
|
||||
public interface UserService {
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*
|
||||
* @param reqDTO 用户创建信息
|
||||
* @return 用户ID
|
||||
*/
|
||||
Long createUser(UserCreateReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*
|
||||
* @param reqDTO 用户更新信息
|
||||
*/
|
||||
void updateUser(UserUpdateReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*
|
||||
* @param id 用户ID
|
||||
*/
|
||||
void deleteUser(Long id);
|
||||
|
||||
/**
|
||||
* 获取用户详情
|
||||
*
|
||||
* @param id 用户ID
|
||||
* @return 用户详情
|
||||
*/
|
||||
UserRespDTO getUser(Long id);
|
||||
|
||||
/**
|
||||
* 获取用户详情
|
||||
*
|
||||
* @param username 用户名
|
||||
* @return 用户详情
|
||||
*/
|
||||
UserRespDTO getUserByUsername(String username);
|
||||
|
||||
/**
|
||||
* 获取用户分页列表
|
||||
*
|
||||
* @param reqDTO 查询条件
|
||||
* @return 用户分页列表
|
||||
*/
|
||||
List<UserRespDTO> getUserPage(UserPageReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 重置用户密码
|
||||
*
|
||||
* @param id 用户ID
|
||||
* @param password 新密码
|
||||
*/
|
||||
void resetUserPassword(Long id, String password);
|
||||
|
||||
/**
|
||||
* 更新用户状态
|
||||
*
|
||||
* @param id 用户ID
|
||||
* @param status 新状态
|
||||
*/
|
||||
void updateUserStatus(Long id, Integer status);
|
||||
|
||||
/**
|
||||
* 获取用户的角色ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色ID列表
|
||||
*/
|
||||
List<Long> getUserRoleIds(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户的角色名称列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色名称列表
|
||||
*/
|
||||
List<String> getUserRoleNames(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户的角色编码列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色编码列表
|
||||
*/
|
||||
List<String> getUserRoleCodes(Long userId);
|
||||
|
||||
/**
|
||||
* 注册用户
|
||||
*
|
||||
* @param reqDTO 注册信息
|
||||
* @return 用户ID
|
||||
*/
|
||||
Long registerUser(UserRegisterReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*
|
||||
* @return 用户详情
|
||||
*/
|
||||
UserRespDTO getCurrentUser();
|
||||
|
||||
/**
|
||||
* 验证用户密码
|
||||
*
|
||||
* @param rawPassword 原始密码
|
||||
* @param encodedPassword 编码后的密码
|
||||
* @return 是否匹配
|
||||
*/
|
||||
boolean validatePassword(String rawPassword, String encodedPassword);
|
||||
|
||||
/**
|
||||
* 加密密码
|
||||
*
|
||||
* @param rawPassword 原始密码
|
||||
* @return 加密后的密码
|
||||
*/
|
||||
String encodePassword(String rawPassword);
|
||||
|
||||
/**
|
||||
* 更新用户登录信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param ip 登录IP
|
||||
*/
|
||||
void updateLoginInfo(Long userId, String ip);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性
|
||||
## 感谢复旦核博士的建议!灰子哥,牛皮!
|
||||
FROM eclipse-temurin:21-jre
|
||||
|
||||
## 创建目录,并使用它作为工作目录
|
||||
RUN mkdir -p /yudao-module-user-biz
|
||||
WORKDIR /yudao-module-user-biz
|
||||
## 将后端项目的 Jar 文件,复制到镜像中
|
||||
COPY ./target/yudao-module-user-biz.jar app.jar
|
||||
|
||||
## 设置 TZ 时区
|
||||
## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
|
||||
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx512m"
|
||||
|
||||
## 暴露后端项目的 48080 端口
|
||||
EXPOSE 48081
|
||||
|
||||
## 启动后端项目
|
||||
CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar
|
||||
@@ -1,10 +0,0 @@
|
||||
# Getting Started
|
||||
|
||||
### Reference Documentation
|
||||
|
||||
For further reference, please consider the following sections:
|
||||
|
||||
* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
|
||||
* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/)
|
||||
* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/#build-image)
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-module-user</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>tashow-module-user-biz</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
system 模块下,我们放通用业务,支撑上层的核心业务。
|
||||
例如说:用户、部门、权限、数据字典等等
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Cloud 基础 -->
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-framework-env</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖服务 -->
|
||||
<!-- <dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-module-system-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-module-infra-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>-->
|
||||
|
||||
<!-- 业务组件 -->
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-data-permission</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-framework-tenant</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-framework-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-data-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-framework-rpc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 注册中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Config 配置中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Job 定时任务相关 -->
|
||||
<!-- <dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-framework-job</artifactId>
|
||||
</dependency>-->
|
||||
|
||||
<!-- 消息队列相关
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-framework-mq</artifactId>
|
||||
</dependency> -->
|
||||
|
||||
<!-- 服务保障相关 TODO 芋艿:暂时去掉 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.tashow.cloud</groupId>-->
|
||||
<!-- <artifactId>yudao-spring-boot-starter-protection</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<!-- <dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-data-excel</artifactId>
|
||||
</dependency> -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 监控相关 -->
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-framework-monitor</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 三方云服务相关 -->
|
||||
<dependency>
|
||||
<groupId>com.xingyuv</groupId>
|
||||
<artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.xingyuv</groupId>
|
||||
<artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-extra</artifactId> <!-- 邮件 -->
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Sa-Token 权限认证(Reactor响应式集成),在线文档:https://sa-token.cc -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-reactor-spring-boot3-starter</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 插件:整合SSO -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-sso</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token OAuth2.0 模块 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-oauth2</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-redis-jackson</artifactId>
|
||||
<version>1.42.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.dtflys.forest</groupId>
|
||||
<artifactId>forest-spring-boot-starter</artifactId>
|
||||
<version>1.5.26</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 视图引擎(在前后端不分离模式下提供视图支持) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.tashow.cloud</groupId>
|
||||
<artifactId>tashow-module-user-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- 设置构建的 jar 包名 -->
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<!-- 打包 -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz;
|
||||
|
||||
import cn.dev33.satoken.sso.SaSsoManager;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class TashowModuleUserBizApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TashowModuleUserBizApplication.class, args);
|
||||
System.out.println();
|
||||
System.out.println("---------------------- Sa-Token SSO 统一认证中心启动成功 ----------------------");
|
||||
System.out.println("配置信息:" + SaSsoManager.getServerConfig());
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* MyBatis Plus配置类
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan("com.tashow.cloud.tashowmoduleuserbiz.mapper")
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
/**
|
||||
* 配置分页插件
|
||||
*/
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
// 添加分页插件
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import com.tashow.cloud.service.SystemRoleService;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 角色管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/role")
|
||||
public class RoleController {
|
||||
|
||||
@Autowired
|
||||
private SystemRoleService roleService;
|
||||
|
||||
/**
|
||||
* 创建角色
|
||||
*/
|
||||
@PostMapping
|
||||
@SaCheckPermission("system:role:create")
|
||||
public SaResult createRole(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
SystemRole role = new SystemRole();
|
||||
role.setName((String) params.get("name"));
|
||||
role.setCode((String) params.get("code"));
|
||||
role.setSort((Integer) params.get("sort"));
|
||||
role.setStatus((Integer) params.get("status"));
|
||||
role.setType((Integer) params.get("type"));
|
||||
role.setRemark((String) params.get("remark"));
|
||||
role.setDataScope((Integer) params.get("dataScope"));
|
||||
role.setDataScopeDeptIds((String) params.get("dataScopeDeptIds"));
|
||||
|
||||
// 设置创建者
|
||||
String username = StpUtil.getLoginIdAsString();
|
||||
role.setCreator(username);
|
||||
role.setUpdater(username);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> menuIds = (List<Long>) params.get("menuIds");
|
||||
|
||||
boolean success = roleService.createRole(role, menuIds);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("角色创建成功").setData(role);
|
||||
} else {
|
||||
return SaResult.error("角色创建失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("角色创建异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新角色
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@SaCheckPermission("system:role:update")
|
||||
public SaResult updateRole(@PathVariable("id") Long id, @RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
SystemRole role = roleService.getRoleById(id);
|
||||
if (role == null) {
|
||||
return SaResult.error("角色不存在");
|
||||
}
|
||||
|
||||
role.setName((String) params.get("name"));
|
||||
role.setCode((String) params.get("code"));
|
||||
role.setSort((Integer) params.get("sort"));
|
||||
role.setStatus((Integer) params.get("status"));
|
||||
role.setType((Integer) params.get("type"));
|
||||
role.setRemark((String) params.get("remark"));
|
||||
role.setDataScope((Integer) params.get("dataScope"));
|
||||
role.setDataScopeDeptIds((String) params.get("dataScopeDeptIds"));
|
||||
|
||||
// 设置更新者
|
||||
String username = StpUtil.getLoginIdAsString();
|
||||
role.setUpdater(username);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> menuIds = (List<Long>) params.get("menuIds");
|
||||
|
||||
boolean success = roleService.updateRole(role, menuIds);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("角色更新成功");
|
||||
} else {
|
||||
return SaResult.error("角色更新失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("角色更新异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@SaCheckPermission("system:role:delete")
|
||||
public SaResult deleteRole(@PathVariable("id") Long id) {
|
||||
try {
|
||||
boolean success = roleService.deleteRole(id);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("角色删除成功");
|
||||
} else {
|
||||
return SaResult.error("角色删除失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("角色删除异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色详情
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@SaCheckPermission("system:role:query")
|
||||
public SaResult getRoleDetail(@PathVariable("id") Long id) {
|
||||
try {
|
||||
SystemRole role = roleService.getRoleById(id);
|
||||
if (role == null) {
|
||||
return SaResult.error("角色不存在");
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("role", role);
|
||||
|
||||
// 获取角色关联的菜单ID列表
|
||||
List<Long> menuIds = roleService.getRoleMenuIds(id);
|
||||
result.put("menuIds", menuIds);
|
||||
|
||||
return SaResult.ok().setData(result);
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("获取角色详情异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@SaCheckPermission("system:role:query")
|
||||
public SaResult getRoleList() {
|
||||
try {
|
||||
List<SystemRole> roles = roleService.getAllRoles();
|
||||
return SaResult.ok().setData(roles);
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("获取角色列表异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用状态的角色列表
|
||||
*/
|
||||
@GetMapping("/options")
|
||||
@PermitAll
|
||||
public SaResult getRoleOptions() {
|
||||
try {
|
||||
List<SystemRole> roles = roleService.getRolesByStatus(0); // 0表示正常状态
|
||||
List<Map<String, Object>> options = roles.stream()
|
||||
.map(role -> {
|
||||
Map<String, Object> option = new HashMap<>();
|
||||
option.put("value", role.getId());
|
||||
option.put("label", role.getName());
|
||||
option.put("code", role.getCode());
|
||||
return option;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return SaResult.ok().setData(options);
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("获取角色选项异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新角色状态
|
||||
*/
|
||||
@PutMapping("/{id}/status")
|
||||
@SaCheckPermission("system:role:update")
|
||||
public SaResult updateRoleStatus(@PathVariable("id") Long id, @RequestParam("status") Integer status) {
|
||||
try {
|
||||
boolean success = roleService.updateRoleStatus(id, status);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("角色状态更新成功");
|
||||
} else {
|
||||
return SaResult.error("角色状态更新失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("角色状态更新异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,310 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.controller;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.tashow.cloud.model.SystemUser;
|
||||
import com.tashow.cloud.service.SystemUserService;
|
||||
import com.tashow.cloud.model.dto.UserRegisterReqDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
public class UserController {
|
||||
|
||||
@Autowired
|
||||
private SystemUserService userService;
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
@SaIgnore
|
||||
@PostMapping("/register")
|
||||
public SaResult register(@Valid @RequestBody UserRegisterReqDTO reqDTO, HttpServletRequest request) {
|
||||
|
||||
// 检查用户名是否已存在
|
||||
SystemUser existingUser = userService.getUserByUsername(reqDTO.getUsername());
|
||||
if (existingUser != null) {
|
||||
return SaResult.error("用户名已被使用");
|
||||
}
|
||||
|
||||
// 加密密码
|
||||
String encodedPassword = userService.encodePassword(reqDTO.getPassword());
|
||||
|
||||
// 创建用户
|
||||
SystemUser user = new SystemUser();
|
||||
user.setUsername(reqDTO.getUsername());
|
||||
user.setPassword(encodedPassword);
|
||||
user.setNickname(reqDTO.getNickname());
|
||||
user.setEmail(reqDTO.getEmail());
|
||||
user.setMobile(reqDTO.getMobile());
|
||||
user.setSex(reqDTO.getSex());
|
||||
user.setStatus(0); // 正常状态
|
||||
|
||||
// 设置登录IP
|
||||
String loginIp = reqDTO.getLoginIp();
|
||||
if (loginIp == null || loginIp.isEmpty()) {
|
||||
loginIp = getClientIp(request);
|
||||
}
|
||||
user.setLoginIp(loginIp);
|
||||
|
||||
// 注册用户
|
||||
boolean success = userService.registerUser(user);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("注册成功");
|
||||
} else {
|
||||
return SaResult.error("注册失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
@PostMapping
|
||||
@SaCheckPermission("system:user:create")
|
||||
public SaResult createUser(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
SystemUser user = new SystemUser();
|
||||
user.setUsername((String) params.get("username"));
|
||||
user.setPassword((String) params.get("password")); // 会在service中加密
|
||||
user.setNickname((String) params.get("nickname"));
|
||||
user.setEmail((String) params.get("email"));
|
||||
user.setMobile((String) params.get("mobile"));
|
||||
user.setRemark((String) params.get("remark"));
|
||||
user.setStatus((Integer) params.get("status"));
|
||||
user.setSex((Integer) params.get("sex"));
|
||||
user.setDeptId((Long) params.get("deptId"));
|
||||
user.setAvatar((String) params.get("avatar"));
|
||||
|
||||
// 设置创建者
|
||||
String username = StpUtil.getLoginIdAsString();
|
||||
user.setCreator(username);
|
||||
user.setUpdater(username);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> roleIds = (List<Long>) params.get("roleIds");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> postIds = (List<Long>) params.get("postIds");
|
||||
|
||||
boolean success = userService.createUser(user, roleIds, postIds);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("用户创建成功").setData(user);
|
||||
} else {
|
||||
return SaResult.error("用户创建失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("用户创建异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@SaCheckPermission("system:user:update")
|
||||
public SaResult updateUser(@PathVariable("id") Long id, @RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
SystemUser user = userService.getUserById(id);
|
||||
if (user == null) {
|
||||
return SaResult.error("用户不存在");
|
||||
}
|
||||
|
||||
user.setNickname((String) params.get("nickname"));
|
||||
user.setEmail((String) params.get("email"));
|
||||
user.setMobile((String) params.get("mobile"));
|
||||
user.setRemark((String) params.get("remark"));
|
||||
user.setStatus((Integer) params.get("status"));
|
||||
user.setSex((Integer) params.get("sex"));
|
||||
user.setDeptId((Long) params.get("deptId"));
|
||||
user.setAvatar((String) params.get("avatar"));
|
||||
|
||||
// 设置更新者
|
||||
String username = StpUtil.getLoginIdAsString();
|
||||
user.setUpdater(username);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> roleIds = (List<Long>) params.get("roleIds");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> postIds = (List<Long>) params.get("postIds");
|
||||
|
||||
boolean success = userService.updateUser(user, roleIds, postIds);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("用户更新成功");
|
||||
} else {
|
||||
return SaResult.error("用户更新失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("用户更新异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@SaCheckPermission("system:user:delete")
|
||||
public SaResult deleteUser(@PathVariable("id") Long id) {
|
||||
try {
|
||||
// 判断是否为当前登录用户
|
||||
Long loginId = StpUtil.getLoginIdAsLong();
|
||||
if (loginId.equals(id)) {
|
||||
return SaResult.error("不能删除当前登录用户");
|
||||
}
|
||||
|
||||
boolean success = userService.deleteUser(id);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("用户删除成功");
|
||||
} else {
|
||||
return SaResult.error("用户删除失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("用户删除异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户详情
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@SaCheckPermission("system:user:query")
|
||||
public SaResult getUserDetail(@PathVariable("id") Long id) {
|
||||
try {
|
||||
SystemUser user = userService.getUserById(id);
|
||||
if (user == null) {
|
||||
return SaResult.error("用户不存在");
|
||||
}
|
||||
|
||||
// 脱敏处理
|
||||
user.setPassword(null);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("user", user);
|
||||
|
||||
// 获取用户角色ID列表
|
||||
List<Long> roleIds = userService.getUserRoleIds(id);
|
||||
result.put("roleIds", roleIds);
|
||||
|
||||
// 获取用户岗位ID列表
|
||||
List<Long> postIds = userService.getUserPostIds(id);
|
||||
result.put("postIds", postIds);
|
||||
|
||||
return SaResult.ok().setData(result);
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("获取用户详情异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*/
|
||||
@GetMapping("/info")
|
||||
public SaResult getCurrentUserInfo() {
|
||||
try {
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
SystemUser user = userService.getUserById(userId);
|
||||
if (user == null) {
|
||||
return SaResult.error("用户不存在");
|
||||
}
|
||||
|
||||
// 脱敏处理
|
||||
user.setPassword(null);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("user", user);
|
||||
|
||||
// 获取用户角色信息
|
||||
List<String> roleCodes = userService.getUserRoleCodes(userId);
|
||||
List<String> roleNames = userService.getUserRoleNames(userId);
|
||||
|
||||
result.put("roles", roleCodes);
|
||||
result.put("roleNames", roleNames);
|
||||
|
||||
return SaResult.ok().setData(result);
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("获取当前用户信息异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置用户密码
|
||||
*/
|
||||
@PutMapping("/{id}/password")
|
||||
@SaCheckPermission("system:user:update")
|
||||
public SaResult resetPassword(@PathVariable("id") Long id, @RequestParam("newPassword") String newPassword) {
|
||||
try {
|
||||
boolean success = userService.resetUserPassword(id, newPassword);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("密码重置成功");
|
||||
} else {
|
||||
return SaResult.error("密码重置失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("密码重置异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户状态
|
||||
*/
|
||||
@PutMapping("/{id}/status")
|
||||
@SaCheckPermission("system:user:update")
|
||||
public SaResult updateUserStatus(@PathVariable("id") Long id, @RequestParam("status") Integer status) {
|
||||
try {
|
||||
// 判断是否为当前登录用户
|
||||
Long loginId = StpUtil.getLoginIdAsLong();
|
||||
if (loginId.equals(id)) {
|
||||
return SaResult.error("不能修改当前登录用户的状态");
|
||||
}
|
||||
|
||||
boolean success = userService.updateUserStatus(id, status);
|
||||
|
||||
if (success) {
|
||||
return SaResult.ok("用户状态更新成功");
|
||||
} else {
|
||||
return SaResult.error("用户状态更新失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return SaResult.error("用户状态更新异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端真实IP地址
|
||||
*/
|
||||
private String getClientIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("X-Real-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
// 多个代理的情况,第一个IP为客户端真实IP
|
||||
if (ip != null && ip.indexOf(",") > 0) {
|
||||
ip = ip.substring(0, ip.indexOf(","));
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.framework.core;
|
||||
|
||||
import com.xingyuv.captcha.service.CaptchaCacheService;
|
||||
import lombok.Setter;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 基于 Redis 实现验证码的存储
|
||||
*
|
||||
* @author 星语
|
||||
*/
|
||||
@Setter
|
||||
public class RedisCaptchaServiceImpl implements CaptchaCacheService {
|
||||
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "redis";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, String value, long expiresInSeconds) {
|
||||
stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String key) {
|
||||
return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String key) {
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
return stringRedisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long increment(String key, long val) {
|
||||
return stringRedisTemplate.opsForValue().increment(key,val);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 系统角色Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SystemRoleMapper extends BaseMapper<SystemRole> {
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tashow.cloud.model.SystemRoleMenu;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 角色菜单关联Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SystemRoleMenuMapper extends BaseMapper<SystemRoleMenu> {
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tashow.cloud.model.SystemUser;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 系统用户Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SystemUserMapper extends BaseMapper<SystemUser> {
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tashow.cloud.model.SystemUserPost;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 用户岗位关联Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SystemUserPostMapper extends BaseMapper<SystemUserPost> {
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tashow.cloud.model.SystemUserRole;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 用户角色关联Mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface SystemUserRoleMapper extends BaseMapper<SystemUserRole> {
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.security.config;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* Sa-Token 配置类
|
||||
*/
|
||||
//@Configuration
|
||||
public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
|
||||
/* *//**
|
||||
* 注册Sa-Token拦截器,打开注解式鉴权功能
|
||||
*//*
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
|
||||
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
|
||||
}*/
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.security.config;
|
||||
|
||||
import com.tashow.cloud.security.security.config.AuthorizeRequestsCustomizer;
|
||||
import com.tashow.cloud.systemapi.enums.ApiConstants;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
|
||||
|
||||
/**
|
||||
* System 模块的 Security 配置
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false, value = "systemSecurityConfiguration")
|
||||
public class SecurityConfiguration {
|
||||
|
||||
@Bean("systemAuthorizeRequestsCustomizer")
|
||||
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
|
||||
return new AuthorizeRequestsCustomizer() {
|
||||
|
||||
@Override
|
||||
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
|
||||
// TODO 芋艿:这个每个项目都需要重复配置,得捉摸有没通用的方案
|
||||
// Swagger 接口文档
|
||||
registry.requestMatchers("/v3/api-docs/**").permitAll()
|
||||
.requestMatchers("/webjars/**").permitAll()
|
||||
.requestMatchers("/swagger-ui").permitAll()
|
||||
.requestMatchers("/swagger-ui/**").permitAll()
|
||||
.requestMatchers("/test").permitAll() ;
|
||||
// Druid 监控
|
||||
registry.requestMatchers("/druid/**").permitAll();
|
||||
// Spring Boot Actuator 的安全配置
|
||||
registry.requestMatchers("/actuator").permitAll()
|
||||
.requestMatchers("/actuator/**").permitAll();
|
||||
// RPC 服务的安全配置
|
||||
registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import com.tashow.cloud.model.SystemRoleMenu;
|
||||
import com.tashow.cloud.model.SystemUserRole;
|
||||
import com.tashow.cloud.service.SystemRoleService;
|
||||
import com.tashow.cloud.tashowmoduleuserbiz.mapper.SystemRoleMapper;
|
||||
import com.tashow.cloud.tashowmoduleuserbiz.mapper.SystemRoleMenuMapper;
|
||||
import com.tashow.cloud.tashowmoduleuserbiz.mapper.SystemUserRoleMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 系统角色服务实现类
|
||||
*/
|
||||
@Service
|
||||
public class SystemRoleServiceImpl extends ServiceImpl<SystemRoleMapper, SystemRole> implements SystemRoleService {
|
||||
|
||||
@Autowired
|
||||
private SystemRoleMenuMapper roleMenuMapper;
|
||||
|
||||
@Autowired
|
||||
private SystemUserRoleMapper userRoleMapper;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean createRole(SystemRole role, List<Long> menuIds) {
|
||||
// 设置默认值
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
role.setCreateTime(now);
|
||||
role.setUpdateTime(now);
|
||||
role.setDeleted(false);
|
||||
role.setTenantId(0L); // 默认租户ID
|
||||
|
||||
// 保存角色
|
||||
boolean saved = save(role);
|
||||
if (!saved) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 保存角色菜单关联
|
||||
if (!CollectionUtils.isEmpty(menuIds)) {
|
||||
batchInsertRoleMenus(role.getId(), menuIds, role.getCreator());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean updateRole(SystemRole role, List<Long> menuIds) {
|
||||
// 更新角色基本信息
|
||||
role.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
// 更新角色
|
||||
boolean updated = updateById(role);
|
||||
if (!updated) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新角色菜单关联
|
||||
if (menuIds != null) {
|
||||
// 先删除旧的关联
|
||||
deleteRoleMenusByRoleId(role.getId());
|
||||
|
||||
// 添加新的关联
|
||||
if (!menuIds.isEmpty()) {
|
||||
batchInsertRoleMenus(role.getId(), menuIds, role.getUpdater());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean deleteRole(Long roleId) {
|
||||
// 逻辑删除角色
|
||||
return removeById(roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemRole getRoleById(Long roleId) {
|
||||
return getById(roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemRole getRoleByCode(String code) {
|
||||
return getOne(new LambdaQueryWrapper<SystemRole>()
|
||||
.eq(SystemRole::getCode, code)
|
||||
.eq(SystemRole::getStatus, 0)
|
||||
.eq(SystemRole::getDeleted, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SystemRole> getAllRoles() {
|
||||
return list(new LambdaQueryWrapper<SystemRole>()
|
||||
.eq(SystemRole::getDeleted, false)
|
||||
.orderByAsc(SystemRole::getSort));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SystemRole> getRolesByStatus(Integer status) {
|
||||
return list(new LambdaQueryWrapper<SystemRole>()
|
||||
.eq(SystemRole::getStatus, status)
|
||||
.eq(SystemRole::getDeleted, false)
|
||||
.orderByAsc(SystemRole::getSort));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色菜单关联(逻辑删除)
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 影响行数
|
||||
*/
|
||||
public int deleteRoleMenus(Long roleId) {
|
||||
// 创建更新条件
|
||||
LambdaUpdateWrapper<SystemRoleMenu> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(SystemRoleMenu::getRoleId, roleId)
|
||||
.eq(SystemRoleMenu::getDeleted, false)
|
||||
.set(SystemRoleMenu::getDeleted, true)
|
||||
.set(SystemRoleMenu::getUpdateTime, LocalDateTime.now());
|
||||
|
||||
// 执行更新
|
||||
return roleMenuMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID删除角色菜单关联(逻辑删除)
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 影响行数
|
||||
*/
|
||||
public int deleteRoleMenusByRoleId(Long roleId) {
|
||||
// 创建更新条件
|
||||
LambdaUpdateWrapper<SystemRoleMenu> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(SystemRoleMenu::getRoleId, roleId)
|
||||
.eq(SystemRoleMenu::getDeleted, false)
|
||||
.set(SystemRoleMenu::getDeleted, true)
|
||||
.set(SystemRoleMenu::getUpdateTime, LocalDateTime.now());
|
||||
|
||||
// 执行更新
|
||||
return roleMenuMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入角色菜单关联
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @param menuIds 菜单ID列表
|
||||
* @param creator 创建者
|
||||
* @return 影响行数
|
||||
*/
|
||||
public int batchInsertRoleMenus(Long roleId, List<Long> menuIds, String creator) {
|
||||
if (CollectionUtils.isEmpty(menuIds)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
List<SystemRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
|
||||
|
||||
for (Long menuId : menuIds) {
|
||||
SystemRoleMenu roleMenu = new SystemRoleMenu();
|
||||
roleMenu.setRoleId(roleId);
|
||||
roleMenu.setMenuId(menuId);
|
||||
roleMenu.setCreator(creator);
|
||||
roleMenu.setUpdater(creator);
|
||||
roleMenu.setCreateTime(now);
|
||||
roleMenu.setUpdateTime(now);
|
||||
roleMenu.setDeleted(false);
|
||||
roleMenu.setTenantId(0L);
|
||||
roleMenus.add(roleMenu);
|
||||
}
|
||||
|
||||
// 批量插入
|
||||
int count = 0;
|
||||
for (SystemRoleMenu roleMenu : roleMenus) {
|
||||
count += roleMenuMapper.insert(roleMenu);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getRoleMenuIds(Long roleId) {
|
||||
// 使用LambdaQueryWrapper查询
|
||||
LambdaQueryWrapper<SystemRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(SystemRoleMenu::getRoleId, roleId)
|
||||
.eq(SystemRoleMenu::getDeleted, false)
|
||||
.select(SystemRoleMenu::getMenuId);
|
||||
|
||||
// 执行查询并转换结果
|
||||
return roleMenuMapper.selectList(queryWrapper)
|
||||
.stream()
|
||||
.map(SystemRoleMenu::getMenuId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID列表获取菜单ID列表
|
||||
*
|
||||
* @param roleIds 角色ID列表
|
||||
* @return 菜单ID列表
|
||||
*/
|
||||
public List<Long> getMenuIdsByRoleIds(List<Long> roleIds) {
|
||||
if (roleIds == null || roleIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 创建查询条件
|
||||
LambdaQueryWrapper<SystemRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.in(SystemRoleMenu::getRoleId, roleIds)
|
||||
.eq(SystemRoleMenu::getDeleted, false)
|
||||
.select(SystemRoleMenu::getMenuId);
|
||||
|
||||
// 执行查询并转换结果,确保唯一性
|
||||
return roleMenuMapper.selectList(queryWrapper)
|
||||
.stream()
|
||||
.map(SystemRoleMenu::getMenuId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SystemRole> getRolesByUserId(Long userId) {
|
||||
// 先获取用户的角色ID列表
|
||||
LambdaQueryWrapper<SystemUserRole> urQueryWrapper = new LambdaQueryWrapper<>();
|
||||
urQueryWrapper.eq(SystemUserRole::getUserId, userId)
|
||||
.eq(SystemUserRole::getDeleted, false)
|
||||
.select(SystemUserRole::getRoleId);
|
||||
|
||||
List<Long> roleIds = userRoleMapper.selectList(urQueryWrapper)
|
||||
.stream()
|
||||
.map(SystemUserRole::getRoleId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (roleIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 然后根据角色ID查询角色信息
|
||||
LambdaQueryWrapper<SystemRole> rQueryWrapper = new LambdaQueryWrapper<>();
|
||||
rQueryWrapper.in(SystemRole::getId, roleIds)
|
||||
.eq(SystemRole::getStatus, 0)
|
||||
.eq(SystemRole::getDeleted, false);
|
||||
|
||||
return baseMapper.selectList(rQueryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateRoleStatus(Long roleId, Integer status) {
|
||||
SystemRole role = new SystemRole();
|
||||
role.setId(roleId);
|
||||
role.setStatus(status);
|
||||
role.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
return updateById(role);
|
||||
}
|
||||
}
|
||||
@@ -1,425 +0,0 @@
|
||||
package com.tashow.cloud.tashowmoduleuserbiz.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.tashow.cloud.model.SystemRole;
|
||||
import com.tashow.cloud.model.SystemUser;
|
||||
import com.tashow.cloud.model.SystemUserRole;
|
||||
import com.tashow.cloud.model.SystemUserPost;
|
||||
import com.tashow.cloud.service.SystemUserService;
|
||||
import com.tashow.cloud.tashowmoduleuserbiz.mapper.SystemUserMapper;
|
||||
import com.tashow.cloud.tashowmoduleuserbiz.mapper.SystemUserRoleMapper;
|
||||
import com.tashow.cloud.tashowmoduleuserbiz.mapper.SystemUserPostMapper;
|
||||
import com.tashow.cloud.tashowmoduleuserbiz.mapper.SystemRoleMapper;
|
||||
import com.tashow.cloud.convert.SystemRoleConvert;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 系统用户服务实现类
|
||||
* 基于MyBatis Plus的查询方式实现
|
||||
*/
|
||||
@Service
|
||||
public class SystemUserServiceImpl extends ServiceImpl<SystemUserMapper, SystemUser> implements SystemUserService {
|
||||
|
||||
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
|
||||
@Autowired
|
||||
private SystemUserRoleMapper userRoleMapper;
|
||||
|
||||
@Autowired
|
||||
private SystemUserPostMapper userPostMapper;
|
||||
|
||||
@Autowired
|
||||
private SystemRoleMapper roleMapper;
|
||||
|
||||
@Override
|
||||
public SystemUser getUserByUsername(String username) {
|
||||
return getOne(new LambdaQueryWrapper<SystemUser>()
|
||||
.eq(SystemUser::getUsername, username)
|
||||
.eq(SystemUser::getStatus, 0)
|
||||
.eq(SystemUser::getDeleted, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validatePassword(String rawPassword, String encodedPassword) {
|
||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemUser getUserById(Long userId) {
|
||||
return getById(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLoginInfo(Long userId, String ip) {
|
||||
SystemUser user = new SystemUser();
|
||||
user.setId(userId);
|
||||
user.setLoginIp(ip);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
user.setLoginDate(now);
|
||||
user.setUpdateTime(now);
|
||||
updateById(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerUser(SystemUser user) {
|
||||
// 设置默认值
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
user.setCreateTime(now);
|
||||
user.setUpdateTime(now);
|
||||
user.setLoginDate(now);
|
||||
user.setCreator("system");
|
||||
user.setUpdater("system");
|
||||
|
||||
if (user.getAvatar() == null || user.getAvatar().isEmpty()) {
|
||||
user.setAvatar("https://sa-token.cc/logo.png"); // 设置默认头像
|
||||
}
|
||||
|
||||
user.setTenantId(0L); // 默认租户ID
|
||||
user.setDeleted(false); // 设置为未删除
|
||||
|
||||
return save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodePassword(String rawPassword) {
|
||||
return passwordEncoder.encode(rawPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean createUser(SystemUser user, List<Long> roleIds, List<Long> postIds) {
|
||||
// 设置默认值
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
user.setCreateTime(now);
|
||||
user.setUpdateTime(now);
|
||||
user.setLoginDate(now);
|
||||
|
||||
if (user.getAvatar() == null || user.getAvatar().isEmpty()) {
|
||||
user.setAvatar("https://sa-token.cc/logo.png"); // 设置默认头像
|
||||
}
|
||||
|
||||
user.setTenantId(0L); // 默认租户ID
|
||||
user.setDeleted(false); // 设置为未删除
|
||||
|
||||
// 加密密码
|
||||
user.setPassword(encodePassword(user.getPassword()));
|
||||
|
||||
// 保存用户
|
||||
boolean saved = save(user);
|
||||
if (!saved) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 保存用户角色关联
|
||||
if (!CollectionUtils.isEmpty(roleIds)) {
|
||||
batchInsertUserRoles(user.getId(), roleIds, user.getCreator());
|
||||
}
|
||||
|
||||
// 保存用户岗位关联
|
||||
if (!CollectionUtils.isEmpty(postIds)) {
|
||||
batchInsertUserPosts(user.getId(), postIds, user.getCreator());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean updateUser(SystemUser user, List<Long> roleIds, List<Long> postIds) {
|
||||
// 更新用户基本信息
|
||||
user.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
// 防止修改密码
|
||||
user.setPassword(null);
|
||||
|
||||
// 更新用户
|
||||
boolean updated = updateById(user);
|
||||
if (!updated) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新用户角色关联
|
||||
if (roleIds != null) {
|
||||
// 先删除旧的关联
|
||||
deleteUserRolesByUserId(user.getId());
|
||||
|
||||
// 添加新的关联
|
||||
if (!roleIds.isEmpty()) {
|
||||
batchInsertUserRoles(user.getId(), roleIds, user.getUpdater());
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户岗位关联
|
||||
if (postIds != null) {
|
||||
// 先删除旧的关联
|
||||
deleteUserPostsByUserId(user.getId());
|
||||
|
||||
// 添加新的关联
|
||||
if (!postIds.isEmpty()) {
|
||||
batchInsertUserPosts(user.getId(), postIds, user.getUpdater());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean deleteUser(Long userId) {
|
||||
// 逻辑删除用户
|
||||
return removeById(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resetUserPassword(Long userId, String newPassword) {
|
||||
SystemUser user = new SystemUser();
|
||||
user.setId(userId);
|
||||
user.setPassword(encodePassword(newPassword));
|
||||
user.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
return updateById(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateUserStatus(Long userId, Integer status) {
|
||||
SystemUser user = new SystemUser();
|
||||
user.setId(userId);
|
||||
user.setStatus(status);
|
||||
user.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
return updateById(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户角色关联(逻辑删除)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 影响行数
|
||||
*/
|
||||
public int deleteUserRoles(Long userId) {
|
||||
// 创建更新条件
|
||||
LambdaUpdateWrapper<SystemUserRole> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(SystemUserRole::getUserId, userId)
|
||||
.eq(SystemUserRole::getDeleted, false)
|
||||
.set(SystemUserRole::getDeleted, true)
|
||||
.set(SystemUserRole::getUpdateTime, LocalDateTime.now());
|
||||
|
||||
// 执行更新
|
||||
return userRoleMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 根据用户ID删除用户角色关联(逻辑删除)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 影响行数
|
||||
*/
|
||||
public int deleteUserRolesByUserId(Long userId) {
|
||||
// 创建更新条件
|
||||
LambdaUpdateWrapper<SystemUserRole> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(SystemUserRole::getUserId, userId)
|
||||
.eq(SystemUserRole::getDeleted, false)
|
||||
.set(SystemUserRole::getDeleted, true)
|
||||
.set(SystemUserRole::getUpdateTime, LocalDateTime.now());
|
||||
|
||||
// 执行更新
|
||||
return userRoleMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID删除用户岗位关联(逻辑删除)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 影响行数
|
||||
*/
|
||||
public int deleteUserPostsByUserId(Long userId) {
|
||||
// 创建更新条件
|
||||
LambdaUpdateWrapper<SystemUserPost> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(SystemUserPost::getUserId, userId)
|
||||
.eq(SystemUserPost::getDeleted, false)
|
||||
.set(SystemUserPost::getDeleted, true)
|
||||
.set(SystemUserPost::getUpdateTime, LocalDateTime.now());
|
||||
|
||||
// 执行更新
|
||||
return userPostMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入用户角色关联
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param roleIds 角色ID列表
|
||||
* @param creator 创建者
|
||||
* @return 影响行数
|
||||
*/
|
||||
public int batchInsertUserRoles(Long userId, List<Long> roleIds, String creator) {
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
List<SystemUserRole> userRoles = new ArrayList<>(roleIds.size());
|
||||
|
||||
for (Long roleId : roleIds) {
|
||||
SystemUserRole userRole = new SystemUserRole();
|
||||
userRole.setUserId(userId);
|
||||
userRole.setRoleId(roleId);
|
||||
userRole.setCreator(creator);
|
||||
userRole.setUpdater(creator);
|
||||
userRole.setCreateTime(now);
|
||||
userRole.setUpdateTime(now);
|
||||
userRole.setDeleted(false);
|
||||
userRole.setTenantId(0L);
|
||||
userRoles.add(userRole);
|
||||
}
|
||||
|
||||
// 批量插入
|
||||
int count = 0;
|
||||
for (SystemUserRole userRole : userRoles) {
|
||||
count += userRoleMapper.insert(userRole);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入用户岗位关联
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param postIds 岗位ID列表
|
||||
* @param creator 创建者
|
||||
* @return 影响行数
|
||||
*/
|
||||
public int batchInsertUserPosts(Long userId, List<Long> postIds, String creator) {
|
||||
if (CollectionUtils.isEmpty(postIds)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
List<SystemUserPost> userPosts = new ArrayList<>(postIds.size());
|
||||
|
||||
for (Long postId : postIds) {
|
||||
SystemUserPost userPost = new SystemUserPost();
|
||||
userPost.setUserId(userId);
|
||||
userPost.setPostId(postId);
|
||||
userPost.setCreator(creator);
|
||||
userPost.setUpdater(creator);
|
||||
userPost.setCreateTime(now);
|
||||
userPost.setUpdateTime(now);
|
||||
userPost.setDeleted(false);
|
||||
userPost.setTenantId(0L);
|
||||
userPosts.add(userPost);
|
||||
}
|
||||
|
||||
// 批量插入
|
||||
int count = 0;
|
||||
for (SystemUserPost userPost : userPosts) {
|
||||
count += userPostMapper.insert(userPost);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户岗位关联(逻辑删除)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 影响行数
|
||||
*/
|
||||
public int deleteUserPosts(Long userId) {
|
||||
// 创建更新条件
|
||||
LambdaUpdateWrapper<SystemUserPost> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(SystemUserPost::getUserId, userId)
|
||||
.eq(SystemUserPost::getDeleted, false)
|
||||
.set(SystemUserPost::getDeleted, true)
|
||||
.set(SystemUserPost::getUpdateTime, LocalDateTime.now());
|
||||
|
||||
// 执行更新
|
||||
return userPostMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getUserRoleIds(Long userId) {
|
||||
// 使用LambdaQueryWrapper查询
|
||||
LambdaQueryWrapper<SystemUserRole> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(SystemUserRole::getUserId, userId)
|
||||
.eq(SystemUserRole::getDeleted, false)
|
||||
.select(SystemUserRole::getRoleId);
|
||||
|
||||
return userRoleMapper.selectList(queryWrapper)
|
||||
.stream()
|
||||
.map(SystemUserRole::getRoleId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUserRoleNames(Long userId) {
|
||||
// 先获取用户角色
|
||||
List<SystemRole> roles = getUserRoles(userId);
|
||||
|
||||
// 提取角色名称
|
||||
return roles.stream()
|
||||
.map(SystemRole::getName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUserRoleCodes(Long userId) {
|
||||
// 先获取用户角色
|
||||
List<SystemRole> roles = getUserRoles(userId);
|
||||
|
||||
// 提取角色编码
|
||||
return roles.stream()
|
||||
.map(SystemRole::getCode)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户角色列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色列表
|
||||
*/
|
||||
private List<SystemRole> getUserRoles(Long userId) {
|
||||
// 先获取用户的角色ID列表
|
||||
List<Long> roleIds = getUserRoleIds(userId);
|
||||
if (roleIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 查询这些角色的详细信息
|
||||
LambdaQueryWrapper<SystemRole> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.in(SystemRole::getId, roleIds)
|
||||
.eq(SystemRole::getStatus, 0)
|
||||
.eq(SystemRole::getDeleted, false);
|
||||
|
||||
return roleMapper.selectList(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getUserPostIds(Long userId) {
|
||||
// 使用LambdaQueryWrapper查询
|
||||
LambdaQueryWrapper<SystemUserPost> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(SystemUserPost::getUserId, userId)
|
||||
.eq(SystemUserPost::getDeleted, false)
|
||||
.select(SystemUserPost::getPostId);
|
||||
|
||||
// 执行查询并转换结果
|
||||
return userPostMapper.selectList(queryWrapper)
|
||||
.stream()
|
||||
.map(SystemUserPost::getPostId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
com.tashow.cloud.tashowmoduleuserbiz.framework.core.RedisCaptchaServiceImpl
|
||||
@@ -1,66 +0,0 @@
|
||||
--- #################### 注册中心 + 配置中心相关配置 ####################
|
||||
|
||||
spring:
|
||||
cloud:
|
||||
nacos:
|
||||
server-addr: 43.139.42.137:8848 # Nacos 服务器地址
|
||||
username: nacos # Nacos 账号
|
||||
password: nacos # Nacos 密码
|
||||
discovery: # 【配置中心】配置项
|
||||
namespace: 5c8b8fe6-9a89-4ae3-975e-ef3bf560ff82 # 命名空间。这里使用 dev 开发环境
|
||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||
metadata:
|
||||
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
|
||||
config: # 【注册中心】配置项
|
||||
namespace: 5c8b8fe6-9a89-4ae3-975e-ef3bf560ff82 # 命名空间。这里使用 dev 开发环境
|
||||
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
|
||||
|
||||
|
||||
|
||||
# 数据源配置项
|
||||
autoconfigure:
|
||||
exclude:
|
||||
- de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置
|
||||
datasource:
|
||||
druid: # Druid 【监控】相关的全局配置
|
||||
web-stat-filter:
|
||||
enabled: true
|
||||
stat-view-servlet:
|
||||
enabled: true
|
||||
allow: # 设置白名单,不填则允许所有访问
|
||||
url-pattern: /druid/*
|
||||
login-username: # 控制台管理用户名和密码
|
||||
login-password:
|
||||
filter:
|
||||
stat:
|
||||
enabled: true
|
||||
log-slow-sql: true # 慢 SQL 记录
|
||||
slow-sql-millis: 100
|
||||
merge-sql: true
|
||||
wall:
|
||||
config:
|
||||
multi-statement-allow: true
|
||||
dynamic: # 多数据源配置
|
||||
druid: # Druid 【连接池】相关的全局配置
|
||||
initial-size: 1 # 初始连接数
|
||||
min-idle: 1 # 最小连接池数量
|
||||
max-active: 20 # 最大连接池数量
|
||||
max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
|
||||
time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
|
||||
min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
|
||||
max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
|
||||
validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
|
||||
test-while-idle: true
|
||||
test-on-borrow: false
|
||||
test-on-return: false
|
||||
primary: master
|
||||
datasource:
|
||||
master:
|
||||
url: jdbc:mysql://43.139.42.137:8406/tashow-platform?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
|
||||
username: tashow-platform
|
||||
password: tashow123,
|
||||
# slave: # 模拟从库,可根据自己需要修改
|
||||
# lazy: true # 开启懒加载,保证启动速度
|
||||
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
|
||||
# username: root
|
||||
# password: 123456
|
||||
@@ -1,229 +0,0 @@
|
||||
server:
|
||||
port: 48082
|
||||
spring:
|
||||
application:
|
||||
name: user-server
|
||||
profiles:
|
||||
active: local
|
||||
main:
|
||||
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
|
||||
allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务
|
||||
config:
|
||||
import:
|
||||
- optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置
|
||||
- optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置
|
||||
# Servlet 配置
|
||||
servlet:
|
||||
# 文件上传相关配置项
|
||||
multipart:
|
||||
max-file-size: 16MB # 单个文件大小
|
||||
max-request-size: 32MB # 设置总上传的文件大小
|
||||
# Jackson 配置项
|
||||
jackson:
|
||||
serialization:
|
||||
write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
|
||||
write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
|
||||
write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
|
||||
fail-on-empty-beans: false # 允许序列化无属性的 Bean
|
||||
# Cache 配置项
|
||||
cache:
|
||||
type: REDIS
|
||||
redis:
|
||||
time-to-live: 1h # 设置过期时间为 1 小时
|
||||
|
||||
|
||||
logging:
|
||||
file:
|
||||
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
|
||||
|
||||
--- #################### 接口文档配置 ####################
|
||||
|
||||
springdoc:
|
||||
api-docs:
|
||||
enabled: true # 1. 是否开启 Swagger 接文档的元数据
|
||||
path: /v3/api-docs
|
||||
swagger-ui:
|
||||
enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面
|
||||
path: /swagger-ui
|
||||
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
|
||||
|
||||
knife4j:
|
||||
enable: true # 2.2 是否开启 Swagger 文档的 Knife4j UI 界面
|
||||
setting:
|
||||
language: zh_cn
|
||||
|
||||
# MyBatis Plus 的配置项
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true #虽然默认为 true ,但是还是显示去指定下。
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: NONE # "智能"模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。
|
||||
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
|
||||
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
|
||||
banner: false # 关闭控制台的 Banner 打印
|
||||
type-aliases-package: ${tashow.info.base-package}.dal.dataobject
|
||||
encryptor:
|
||||
password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成
|
||||
|
||||
mybatis-plus-join:
|
||||
banner: false # 关闭控制台的 Banner 打印
|
||||
|
||||
# Spring Data Redis 配置
|
||||
spring:
|
||||
data:
|
||||
redis:
|
||||
repositories:
|
||||
enabled: false # 项目未使用到 Spring Data Redis 的 Repository,所以直接禁用,保证启动速度
|
||||
|
||||
|
||||
|
||||
|
||||
# VO 转换(数据翻译)相关
|
||||
easy-trans:
|
||||
is-enable-global: true # 启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口
|
||||
|
||||
--- #################### RPC 远程调用相关配置 ####################
|
||||
|
||||
--- #################### 消息队列相关 ####################
|
||||
spring:
|
||||
# Kafka 配置项,对应 KafkaProperties 配置类
|
||||
kafka:
|
||||
# Kafka Producer 配置项
|
||||
producer:
|
||||
acks: 1 # 0-不应答。1-leader 应答。all-所有 leader 和 follower 应答。
|
||||
retries: 3 # 发送失败时,重试发送的次数
|
||||
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer # 消息的 value 的序列化
|
||||
# Kafka Consumer 配置项
|
||||
consumer:
|
||||
auto-offset-reset: earliest # 设置消费者分组最初的消费进度为 earliest 。可参考博客 https://blog.csdn.net/lishuangzhe7047/article/details/74530417 理解
|
||||
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
|
||||
properties:
|
||||
spring.json.trusted.packages: '*'
|
||||
# Kafka Consumer Listener 监听器配置
|
||||
listener:
|
||||
missing-topics-fatal: false # 消费监听接口监听的主题不存在时,默认会报错。所以通过设置为 false ,解决报错
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
xxl:
|
||||
job:
|
||||
executor:
|
||||
appname: ${spring.application.name} # 执行器 AppName
|
||||
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
|
||||
accessToken: default_token # 执行器通讯TOKEN
|
||||
|
||||
--- #################### 验证码相关配置 ####################
|
||||
|
||||
aj:
|
||||
captcha:
|
||||
jigsaw: classpath:images/jigsaw # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径
|
||||
pic-click: classpath:images/pic-click # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径
|
||||
cache-type: redis # 缓存 local/redis...
|
||||
cache-number: 1000 # local 缓存的阈值,达到这个值,清除缓存
|
||||
timing-clear: 180 # local定时清除过期缓存(单位秒),设置为0代表不执行
|
||||
type: blockPuzzle # 验证码类型 default两种都实例化。 blockPuzzle 滑块拼图 clickWord 文字点选
|
||||
water-mark: 他秀 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode
|
||||
interference-options: 0 # 滑动干扰项(0/1/2)
|
||||
req-frequency-limit-enable: false # 接口请求次数一分钟限制是否开启 true|false
|
||||
req-get-lock-limit: 5 # 验证失败5次,get接口锁定
|
||||
req-get-lock-seconds: 10 # 验证失败后,锁定时间间隔
|
||||
req-get-minute-limit: 30 # get 接口一分钟内请求数限制
|
||||
req-check-minute-limit: 60 # check 接口一分钟内请求数限制
|
||||
req-verify-minute-limit: 60 # verify 接口一分钟内请求数限制
|
||||
|
||||
--- #################### 芋道相关配置 ####################
|
||||
|
||||
tashow:
|
||||
info:
|
||||
version: 1.0.0
|
||||
base-package: com.tashow.cloud.system
|
||||
web:
|
||||
admin-ui:
|
||||
url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址
|
||||
xss:
|
||||
enable: false
|
||||
exclude-urls: # 如下 url,仅仅是为了演示,去掉配置也没关系
|
||||
- ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
|
||||
swagger:
|
||||
title: 管理后台
|
||||
description: 提供管理员管理的所有功能
|
||||
version: ${tashow.info.version}
|
||||
tenant: # 多租户相关配置项
|
||||
enable: true
|
||||
ignore-urls:
|
||||
- /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号
|
||||
- /admin-api/system/tenant/get-by-website # 基于域名获取租户,不许带租户编号
|
||||
- /admin-api/system/captcha/get-image # 获取图片验证码,和租户无关
|
||||
- /admin-api/system/captcha/get # 获取图片验证码,和租户无关
|
||||
- /admin-api/system/captcha/check # 校验图片验证码,和租户无关
|
||||
- /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号
|
||||
- /rpc-api/system/tenant/valid # 防止递归。避免调用 /rpc-api/system/tenant/valid 接口时,又去触发 /rpc-api/system/tenant/valid 去校验
|
||||
- /rpc-api/system/tenant/id-list # 获得租户列表的时候,无需传递租户编号
|
||||
- /rpc-api/system/oauth2/token/check # 访问令牌校验时,无需传递租户编号;主要解决上传文件的场景,前端不会传递 tenant-id!
|
||||
ignore-tables:
|
||||
- system_tenant
|
||||
- system_tenant_package
|
||||
- system_dict_data
|
||||
- system_dict_type
|
||||
- system_error_code
|
||||
- system_menu
|
||||
- system_sms_channel
|
||||
- system_sms_template
|
||||
- system_sms_log
|
||||
- system_sensitive_word
|
||||
- system_oauth2_client
|
||||
- system_mail_account
|
||||
- system_mail_template
|
||||
- system_mail_log
|
||||
- system_notify_template
|
||||
ignore-caches:
|
||||
- user_role_ids
|
||||
- permission_menu_ids
|
||||
- oauth_client
|
||||
- notify_template
|
||||
- mail_account
|
||||
- mail_template
|
||||
- sms_template
|
||||
sms-code: # 短信验证码相关的配置项
|
||||
expire-times: 10m
|
||||
send-frequency: 1m
|
||||
send-maximum-quantity-per-day: 10
|
||||
begin-code: 9999 # 这里配置 9999 的原因是,测试方便。
|
||||
end-code: 9999 # 这里配置 9999 的原因是,测试方便。
|
||||
|
||||
debug: false
|
||||
|
||||
|
||||
sa-token:
|
||||
# token名称
|
||||
token-name: satoken
|
||||
# token有效期
|
||||
timeout: 2592000
|
||||
# token临时有效期
|
||||
activity-timeout: -1
|
||||
# 是否允许同一账号并发登录
|
||||
is-concurrent: true
|
||||
# 多人登录时,是否共用一个token
|
||||
is-share: false
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否输出操作日志
|
||||
is-log: false
|
||||
|
||||
# SSO-Client端相关配置
|
||||
sso:
|
||||
# SSO-Server端 统一认证地址
|
||||
auth-url: http://localhost:48082/sso/auth
|
||||
# 是否打开单点注销功能
|
||||
is-slo: true
|
||||
# 单点登录查询ticket参数名称
|
||||
ticket-param-name: ticket
|
||||
# 打开模式三(此值为true时需要配置下面所有参数)
|
||||
is-http: true
|
||||
# 请求秘钥 与SSO-Server端保持一致
|
||||
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||
# SSO-Server端 ticket校验地址
|
||||
check-ticket-url: http://localhost:48082/sso/checkTicket
|
||||
# SSO-Server端 查询userinfo地址
|
||||
userinfo-url: http://localhost:48082/sso/userinfo
|
||||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |