feat: 集成 satoken jwt

1. 登录成功后返回 jwt token
This commit is contained in:
shizhendong
2024-08-02 17:30:19 +08:00
parent 4b53e78124
commit af0d0e55ca
6 changed files with 104 additions and 24 deletions

View File

@@ -79,6 +79,14 @@
<artifactId>sa-token-spring-boot3-starter</artifactId> <artifactId>sa-token-spring-boot3-starter</artifactId>
<version>1.37.0</version> <version>1.37.0</version>
</dependency> </dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>1.37.0</version>
</dependency>
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>

View File

@@ -1,17 +1,23 @@
package net.geedge.asw.common.config; package net.geedge.asw.common.config;
import java.util.concurrent.TimeUnit; import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.jwt.SaJwtTemplate;
import cn.dev33.satoken.jwt.SaJwtUtil;
import cn.dev33.satoken.jwt.StpLogicJwtForStateless;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.jwt.JWT;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import cn.dev33.satoken.config.SaTokenConfig; import java.util.concurrent.TimeUnit;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public class SaTokenConfigure implements WebMvcConfigurer { public class SaTokenConfigure implements WebMvcConfigurer {
@@ -38,6 +44,8 @@ public class SaTokenConfigure implements WebMvcConfigurer {
config.setTokenStyle("simple-uuid"); // token 风格 config.setTokenStyle("simple-uuid"); // token 风格
config.setIsLog(false); // 是否输出操作日志 config.setIsLog(false); // 是否输出操作日志
config.setIsPrint(false); config.setIsPrint(false);
// jwt秘钥
config.setJwtSecretKey("ypCLARItfzxvdVqRwPcwIasdgAkhoubj");
// config.setIsReadCookie(false); // config.setIsReadCookie(false);
} }
@@ -50,4 +58,29 @@ public class SaTokenConfigure implements WebMvcConfigurer {
SaRouter.match("/api/v1/**").notMatch("/api/v1/login").check(r -> StpUtil.checkLogin()); SaRouter.match("/api/v1/**").notMatch("/api/v1/login").check(r -> StpUtil.checkLogin());
})).addPathPatterns("/**"); })).addPathPatterns("/**");
} }
@Bean
public StpLogic getStpLogicJwt() {
// Sa-Token 整合 jwt (Stateless 无状态模式)
return new StpLogicJwtForStateless();
}
/**
* 自定义 SaJwtUtil 生成 token 的算法
*/
@PostConstruct
public void setSaJwtTemplate() {
SaJwtUtil.setSaJwtTemplate(new SaJwtTemplate() {
@Override
public String generateToken(JWT jwt, String keyt) {
// header
jwt.setHeader("alg", "HS256");
jwt.setHeader("typ", "JWT");
// payload
jwt.setPayload("iss", "net.geedge.asw");
return super.generateToken(jwt, keyt);
}
});
}
} }

View File

@@ -8,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import net.geedge.asw.module.app.entity.ApplicationEntity; import net.geedge.asw.module.app.entity.ApplicationEntity;
import net.geedge.asw.module.app.entity.PackageEntity; import net.geedge.asw.module.app.entity.PackageEntity;
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
@Data @Data
@TableName("pcap") @TableName("pcap")
@@ -25,6 +26,9 @@ public class PcapEntity {
private String createUserId; private String createUserId;
private String workspaceId; private String workspaceId;
@TableField(exist = false)
private WorkspaceEntity workspace;
@TableField(exist = false) @TableField(exist = false)
private String jobId; private String jobId;

View File

@@ -26,6 +26,8 @@ import net.geedge.asw.module.runner.util.PcapParserThread;
import net.geedge.asw.module.runner.util.RunnerConstant; import net.geedge.asw.module.runner.util.RunnerConstant;
import net.geedge.asw.module.workbook.service.IWorkbookResourceService; import net.geedge.asw.module.workbook.service.IWorkbookResourceService;
import net.geedge.asw.module.workbook.util.WorkbookConstant; import net.geedge.asw.module.workbook.util.WorkbookConstant;
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
import net.geedge.asw.module.workspace.service.IWorkspaceService;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@@ -64,6 +66,9 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
@Autowired @Autowired
private IWorkbookResourceService workbookResourceService; private IWorkbookResourceService workbookResourceService;
@Autowired
private IWorkspaceService workspaceService;
@Override @Override
public PcapEntity queryInfo(String id) { public PcapEntity queryInfo(String id) {
PcapEntity pcap = this.getById(id); PcapEntity pcap = this.getById(id);
@@ -180,6 +185,9 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
for (String id : ids) { for (String id : ids) {
PcapEntity pcapEntity = this.getById(id); PcapEntity pcapEntity = this.getById(id);
if (T.ObjectUtil.isNotNull(pcapEntity)) { if (T.ObjectUtil.isNotNull(pcapEntity)) {
WorkspaceEntity workspace = workspaceService.getById(pcapEntity.getWorkspaceId());
pcapEntity.setWorkspace(workspace);
PcapParserThread pcapParserThread = new PcapParserThread(); PcapParserThread pcapParserThread = new PcapParserThread();
pcapParserThread.setPcapEntity(pcapEntity); pcapParserThread.setPcapEntity(pcapEntity);
taskList.add(pcapParserThread); taskList.add(pcapParserThread);

View File

@@ -17,7 +17,6 @@ import org.opensearch.client.opensearch.core.BulkRequest;
import org.opensearch.client.opensearch.core.BulkResponse; import org.opensearch.client.opensearch.core.BulkResponse;
import org.opensearch.client.opensearch.core.bulk.BulkResponseItem; import org.opensearch.client.opensearch.core.bulk.BulkResponseItem;
import org.opensearch.client.opensearch.indices.CreateIndexRequest; import org.opensearch.client.opensearch.indices.CreateIndexRequest;
import org.opensearch.client.opensearch.indices.DeleteIndexRequest;
import org.opensearch.client.opensearch.indices.ExistsRequest; import org.opensearch.client.opensearch.indices.ExistsRequest;
import org.opensearch.client.opensearch.indices.IndexSettings; import org.opensearch.client.opensearch.indices.IndexSettings;
@@ -153,10 +152,8 @@ public class PcapParserThread implements Runnable {
* @param jsonArray * @param jsonArray
*/ */
private void uploadToOpenSearch(JSONArray jsonArray) { private void uploadToOpenSearch(JSONArray jsonArray) {
String pcapPath = pcapEntity.getPath(); String workspaceName = pcapEntity.getWorkspace().getName();
String md5Hex = T.DigestUtil.md5Hex(T.FileUtil.file(pcapPath)); String indexName = String.format("workspace-%s", workspaceName);
String indexName = String.format("session-%s", md5Hex);
try { try {
// check if index exists // check if index exists
boolean indexExists = openSearchClient.indices() boolean indexExists = openSearchClient.indices()
@@ -165,25 +162,23 @@ public class PcapParserThread implements Runnable {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("[uploadToOpenSearch] [index: {}] [exists: {}]", indexName, indexExists); log.debug("[uploadToOpenSearch] [index: {}] [exists: {}]", indexName, indexExists);
} }
// if index exists, delete // if index not exists, create index with default settings
if (indexExists) { if (!indexExists) {
openSearchClient.indices().delete(new DeleteIndexRequest.Builder().index(indexName).build()); openSearchClient.indices().create(
log.debug("[uploadToOpenSearch] [index: {}] [deleted]", indexName); new CreateIndexRequest.Builder()
.index(indexName)
.settings(new IndexSettings.Builder().build())
.build()
);
log.debug("[uploadToOpenSearch] [index: {}] [created]", indexName);
} }
// create index with default settings
openSearchClient.indices().create(
new CreateIndexRequest.Builder()
.index(indexName)
.settings(new IndexSettings.Builder().build())
.build()
);
// upload data in bulk // upload data in bulk
BulkRequest.Builder br = new BulkRequest.Builder(); BulkRequest.Builder br = new BulkRequest.Builder();
String pcapId = pcapEntity.getId();
for (int i = 0; i < jsonArray.size(); i++) { for (int i = 0; i < jsonArray.size(); i++) {
JSONObject jsonObject = (JSONObject) jsonArray.get(i); JSONObject jsonObject = (JSONObject) jsonArray.get(i);
String id = String.valueOf(i); String id = pcapId + "-" + String.valueOf(i);
br.operations(op -> op.index( br.operations(op -> op.index(
idx -> idx.index(indexName) idx -> idx.index(indexName)
.id(id) .id(id)

View File

@@ -1,7 +1,11 @@
package net.geedge.asw.module.sys.controller; package net.geedge.asw.module.sys.controller;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.signers.JWTSignerUtil;
import net.geedge.asw.common.util.R; import net.geedge.asw.common.util.R;
import net.geedge.asw.common.util.RCode; import net.geedge.asw.common.util.RCode;
import net.geedge.asw.common.util.T; import net.geedge.asw.common.util.T;
@@ -10,7 +14,9 @@ import net.geedge.asw.module.sys.service.ISysAuthService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping("/api/v1") @RequestMapping("/api/v1")
@@ -19,6 +25,9 @@ public class SysAuthController {
@Autowired @Autowired
private ISysAuthService authService; private ISysAuthService authService;
@Autowired
private SaTokenConfig saTokenConfig;
record AuthRecord(String userName, String pwd) {} record AuthRecord(String userName, String pwd) {}
@PostMapping("/login") @PostMapping("/login")
@@ -27,6 +36,29 @@ public class SysAuthController {
.notEmpty(RCode.SYS_USER_PWD_ERROR); .notEmpty(RCode.SYS_USER_PWD_ERROR);
SysUserEntity userEntity = authService.login(record.userName(), record.pwd()); SysUserEntity userEntity = authService.login(record.userName(), record.pwd());
SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
String tokenValue = tokenInfo.getTokenValue();
JWT jwt = JWTUtil.parseToken(tokenValue);
// payload
jwt.setPayload("sub", userEntity.getUserName());
Map<String, Object> permissions = authService.userPermissions();
String roles = ((List<String>) T.JSONUtil.getByPath(T.JSONUtil.parse(permissions), "records.role.name")).stream()
.distinct()
.collect(Collectors.joining(","));
jwt.setPayload("roles", roles);
Long eff = Long.valueOf(jwt.getPayload("eff").toString());
jwt.setPayload("exp", eff == -1L ? -1 : (eff / 1000));
jwt.setPayload("iat", System.currentTimeMillis() / 1000);
jwt.setPayload("nbf", System.currentTimeMillis() / 1000);
String sign = jwt.sign(JWTSignerUtil.hs256(saTokenConfig.getJwtSecretKey().getBytes()));
tokenInfo.setTokenValue(sign);
userEntity.setPwd(null); userEntity.setPwd(null);
return R.ok().putData("tokenInfo", tokenInfo).putData("user", userEntity); return R.ok().putData("tokenInfo", tokenInfo).putData("user", userEntity);
} }