初始化

This commit is contained in:
2026-02-22 18:56:10 +08:00
commit 26677972a6
3112 changed files with 255972 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>tech.easyflow</groupId>
<artifactId>easyflow-modules</artifactId>
<version>${revision}</version>
</parent>
<name>easyflow-module-auth</name>
<artifactId>easyflow-module-auth</artifactId>
<dependencies>
<dependency>
<groupId>tech.easyflow</groupId>
<artifactId>easyflow-common-satoken</artifactId>
</dependency>
<dependency>
<groupId>tech.easyflow</groupId>
<artifactId>easyflow-common-web</artifactId>
</dependency>
<dependency>
<groupId>tech.easyflow</groupId>
<artifactId>easyflow-module-system</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,11 @@
package tech.easyflow.auth.config;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@AutoConfiguration
public class AuthModuleConfig {
public AuthModuleConfig() {
System.out.println("启用模块 >>>>>>>>>> module-auth");
}
}

View File

@@ -0,0 +1,88 @@
package tech.easyflow.auth.config;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import tech.easyflow.common.annotation.UsePermission;
public class CurdInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(CurdInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("进入 CurdInterceptor requestURI:{}", requestURI);
String groupName = "";
// 检查handler是否是HandlerMethod类型
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
SaIgnore saIgnoreAnnotation = handlerMethod.getBeanType().getAnnotation(SaIgnore.class);
SaIgnore saIgnoreAnnotationMethod = handlerMethod.getMethodAnnotation(SaIgnore.class);
if (saIgnoreAnnotation != null || saIgnoreAnnotationMethod != null) {
log.info("{}-----------------> 放行: saIgnoreAnnotation:{}", requestURI,saIgnoreAnnotation);
return true;
}
// 获取类上的特定注解
UsePermission classAnnotation = handlerMethod.getBeanType().getAnnotation(UsePermission.class);
if (classAnnotation != null) {
// 处理注解逻辑
groupName = classAnnotation.moduleName();
}
// 有此注解,交给 sa token 自行判断
SaCheckPermission saCheckPermission = handlerMethod.getMethodAnnotation(SaCheckPermission.class);
if (saCheckPermission != null) {
return true;
}
}
String requestUri = request.getRequestURI();
// 查询
String finalGroupName = groupName;
SaRouter.match("/**/list",
"/**/page",
"/**/detail",
"/**/intelligentFilling"
).check(r -> {
checkBaseCurd(requestUri, finalGroupName, "query");
});
// 保存
SaRouter.match("/**/save",
"/**/update"
).check(r -> {
checkBaseCurd(requestUri, finalGroupName, "save");
});
// 删除
SaRouter.match("/**/remove",
"/**/removeBatch"
).check(r -> {
checkBaseCurd(requestUri, finalGroupName, "remove");
});
return true;
}
private void checkBaseCurd(String uri, String groupName, String permission) {
int idx = uri.lastIndexOf("/");
String per = uri.substring(0,idx + 1) + permission;
if (StrUtil.isNotEmpty(groupName)) {
// 如果指定了继承的模块,就改为该模块的权限校验
per = groupName + "/" + permission;
}
StpUtil.checkPermission(per);
}
}

View File

@@ -0,0 +1,42 @@
package tech.easyflow.auth.config;
import cn.dev33.satoken.interceptor.SaInterceptor;
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;
import javax.annotation.Resource;
@Configuration
public class LoginAutoConfig implements WebMvcConfigurer {
@Resource
private LoginProperties properties;
@Resource
private NeedApiKeyInterceptor needApiKeyInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
SaInterceptor saInterceptor = new SaInterceptor(handle -> {
StpUtil.checkLogin();
});
registry.addInterceptor(new CurdInterceptor())
.order(101)
.addPathPatterns("/**");
registry.addInterceptor(saInterceptor)
.order(100)
.addPathPatterns("/**")
.excludePathPatterns("/")
.excludePathPatterns("/error")
.excludePathPatterns("/attachment/**")
.excludePathPatterns("/api/v1/public/*")
.excludePathPatterns("/api/v1/account/login")
.excludePathPatterns("/api/v1/account/register")
.excludePathPatterns("/thirdAuth/**")
.excludePathPatterns("/public-api/**")
.excludePathPatterns(properties.getExcludesOrEmpty());
registry.addInterceptor(needApiKeyInterceptor);
}
}

View File

@@ -0,0 +1,23 @@
package tech.easyflow.auth.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "easyflow.login")
public class LoginProperties {
private String[] excludes;
public String[] getExcludes() {
return excludes;
}
public String[] getExcludesOrEmpty() {
return excludes != null ? excludes : new String[0];
}
public void setExcludes(String[] excludes) {
this.excludes = excludes;
}
}

View File

@@ -0,0 +1,36 @@
package tech.easyflow.auth.config;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import tech.easyflow.common.annotation.NeedApiKeyAccess;
import tech.easyflow.common.util.StringUtil;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.service.SysApiKeyService;
import javax.annotation.Resource;
@Component
public class NeedApiKeyInterceptor implements HandlerInterceptor {
@Resource
private SysApiKeyService sysApiKeyService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
if ( handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
NeedApiKeyAccess needApiKeyAccess = handlerMethod.getMethodAnnotation(NeedApiKeyAccess.class);
if (needApiKeyAccess != null) {
String apiKey = request.getHeader("Authorization");
if (StringUtil.noText(apiKey)) {
throw new BusinessException("请传入apiKey");
}
sysApiKeyService.checkApikeyPermission(apiKey, requestURI);
}
}
return true;
}
}

View File

@@ -0,0 +1,34 @@
package tech.easyflow.auth.entity;
import javax.validation.constraints.NotEmpty;
public class LoginDTO {
/**
* 账号
*/
@NotEmpty(message = "账号不能为空")
private String account;
/**
* 密码
*/
@NotEmpty(message = "密码不能为空")
private String password;
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@@ -0,0 +1,41 @@
package tech.easyflow.auth.entity;
public class LoginVO {
/**
* token
*/
private String token;
/**
* 昵称
*/
private String nickname;
/**
* 头像
*/
private String avatar;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
}

View File

@@ -0,0 +1,11 @@
package tech.easyflow.auth.service;
import tech.easyflow.auth.entity.LoginDTO;
import tech.easyflow.auth.entity.LoginVO;
public interface AuthService {
/**
* 登录
*/
LoginVO login(LoginDTO loginDTO);
}

View File

@@ -0,0 +1,86 @@
package tech.easyflow.auth.service.impl;
import tech.easyflow.auth.entity.LoginDTO;
import tech.easyflow.auth.entity.LoginVO;
import tech.easyflow.auth.service.AuthService;
import tech.easyflow.common.constant.Constants;
import tech.easyflow.common.constant.enums.EnumDataStatus;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.entity.SysAccount;
import tech.easyflow.system.entity.SysMenu;
import tech.easyflow.system.entity.SysRole;
import tech.easyflow.system.service.SysAccountService;
import tech.easyflow.system.service.SysMenuService;
import tech.easyflow.system.service.SysRoleService;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.tenant.TenantManager;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class AuthServiceImpl implements AuthService, StpInterface {
@Resource
private SysAccountService sysAccountService;
@Resource
private SysRoleService sysRoleService;
@Resource
private SysMenuService sysMenuService;
@Override
public LoginVO login(LoginDTO loginDTO) {
LoginVO res = new LoginVO();
try {
TenantManager.ignoreTenantCondition();
String pwd = loginDTO.getPassword();
QueryWrapper w = QueryWrapper.create();
w.eq(SysAccount::getLoginName, loginDTO.getAccount());
SysAccount record = sysAccountService.getOne(w);
if (record == null) {
throw new BusinessException("用户名/密码错误");
}
if (EnumDataStatus.UNAVAILABLE.getCode().equals(record.getStatus())) {
throw new BusinessException("账号未启用,请联系管理员");
}
String pwdDb = record.getPassword();
if (!BCrypt.checkpw(pwd, pwdDb)) {
throw new BusinessException("用户名/密码错误");
}
StpUtil.login(record.getId());
LoginAccount loginAccount = new LoginAccount();
BeanUtil.copyProperties(record, loginAccount);
StpUtil.getSession().set(Constants.LOGIN_USER_KEY, loginAccount);
String tokenValue = StpUtil.getTokenValue();
res.setToken(tokenValue);
res.setNickname(record.getNickname());
res.setAvatar(record.getAvatar());
} finally {
TenantManager.restoreTenantCondition();
}
return res;
}
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
List<SysMenu> menus = sysMenuService.getMenusByAccountId(new SysMenu(), BigInteger.valueOf(Long.parseLong(loginId.toString())));
return menus.stream()
.map(SysMenu::getPermissionTag)
.distinct()
.collect(Collectors.toList());
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
List<SysRole> roles = sysRoleService.getRolesByAccountId(BigInteger.valueOf(Long.parseLong(loginId.toString())));
return roles.stream().map(SysRole::getRoleKey).collect(Collectors.toList());
}
}