初始化
This commit is contained in:
28
easyflow-modules/easyflow-module-auth/pom.xml
Normal file
28
easyflow-modules/easyflow-module-auth/pom.xml
Normal 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>
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user