diff --git a/.gitignore b/.gitignore
index 50e85cf..075e000 100644
--- a/.gitignore
+++ b/.gitignore
@@ -140,3 +140,5 @@ gradle-app.setting
# JDT-specific (Eclipse Java Development Tools)
.classpath
+# Running
+run/
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..4ac183f
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index ccfd51a..b1ac391 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,6 +2,7 @@
+
diff --git a/.idea/modules/clubs.iml b/.idea/modules/clubs.iml
new file mode 100644
index 0000000..f192152
--- /dev/null
+++ b/.idea/modules/clubs.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/mmga/clubs/commands/UserCommands.java b/src/main/java/org/mmga/clubs/commands/UserCommands.java
index a63a40e..7105c2b 100644
--- a/src/main/java/org/mmga/clubs/commands/UserCommands.java
+++ b/src/main/java/org/mmga/clubs/commands/UserCommands.java
@@ -20,12 +20,12 @@ public class UserCommands {
}
@ShellMethod("创建用户")
public void createUser(String name, String password) {
- BaseResponse user = this.userController.createUser(new UserRegVo(name, DigestUtils.md5Hex(password), 1));
+ BaseResponse user = this.userController.createUser(new UserRegVo(name, DigestUtils.md5Hex(password), 1), null);
ShellUtils.logToResult(log, user);
}
@ShellMethod("登录")
public void login(String name, String password) {
- BaseResponse user = this.userController.login(new UserLoginVo(name, DigestUtils.md5Hex(password)));
+ BaseResponse user = this.userController.login(new UserLoginVo(name, DigestUtils.md5Hex(password)), null);
ShellUtils.logToResult(log, user);
}
}
diff --git a/src/main/java/org/mmga/clubs/configuration/ECKeyProviderConfiguration.java b/src/main/java/org/mmga/clubs/configuration/ECKeyProviderConfiguration.java
new file mode 100644
index 0000000..b0b0d6c
--- /dev/null
+++ b/src/main/java/org/mmga/clubs/configuration/ECKeyProviderConfiguration.java
@@ -0,0 +1,81 @@
+package org.mmga.clubs.configuration;
+
+import lombok.SneakyThrows;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+@Configuration
+public class ECKeyProviderConfiguration {
+ private KeyPair keyPair;
+ private ECPublicKey publicKey;
+ private ECPrivateKey privateKey;
+ @SneakyThrows
+ public KeyPair keyPair(){
+ if (this.keyPair != null){
+ return this.keyPair;
+ }
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
+ ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256r1");
+ keyPairGenerator.initialize(ecGenParameterSpec);
+ this.keyPair = keyPairGenerator.generateKeyPair();
+ return this.keyPair;
+ }
+ @SneakyThrows
+ @Bean
+ public ECPublicKey ecPublicKey(){
+ if (this.publicKey == null){
+ File file = new File("jwt_pub.pem");
+ if (file.exists()){
+ FileInputStream publicKeyInputStream = new FileInputStream(file);
+ byte[] publicKeyData = publicKeyInputStream.readAllBytes();
+ publicKeyInputStream.close();
+ KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ this.publicKey = (ECPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyData));
+ }else {
+ this.publicKey = (ECPublicKey) keyPair().getPublic();
+ if (!file.createNewFile()) {
+ throw new RuntimeException("Can't create public key file");
+ }
+ FileOutputStream fileOutputStream = new FileOutputStream(file);
+ fileOutputStream.write(publicKey.getEncoded());
+ fileOutputStream.close();
+ }
+ }
+ return this.publicKey;
+ }
+ @SneakyThrows
+ @Bean
+ public ECPrivateKey ecPrivateKey(){
+ if (this.privateKey == null){
+ File file = new File("jwt_pri.pem");
+ if (file.exists()){
+ FileInputStream publicKeyInputStream = new FileInputStream(file);
+ byte[] publicKeyData = publicKeyInputStream.readAllBytes();
+ publicKeyInputStream.close();
+ KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ this.privateKey = (ECPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(publicKeyData));
+ }else {
+ this.privateKey = (ECPrivateKey) keyPair().getPrivate();
+ if (!file.createNewFile()) {
+ throw new RuntimeException("Can't create private key file");
+ }
+ FileOutputStream fileOutputStream = new FileOutputStream(file);
+ fileOutputStream.write(privateKey.getEncoded());
+ fileOutputStream.close();
+ }
+ }
+ return this.privateKey;
+ }
+}
diff --git a/src/main/java/org/mmga/clubs/controller/UserController.java b/src/main/java/org/mmga/clubs/controller/UserController.java
index f8b30d2..702e41c 100644
--- a/src/main/java/org/mmga/clubs/controller/UserController.java
+++ b/src/main/java/org/mmga/clubs/controller/UserController.java
@@ -3,6 +3,7 @@ package org.mmga.clubs.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.mmga.clubs.entities.BaseResponse;
import org.mmga.clubs.entities.user.User;
@@ -24,12 +25,12 @@ public class UserController {
}
@PostMapping("/login")
@Operation(description = "用户登录", responses = {@ApiResponse(description = "返回是否登录成功", responseCode = "200")})
- public BaseResponse login(@RequestBody UserLoginVo user){
- return service.login(user);
+ public BaseResponse login(@RequestBody UserLoginVo user, HttpServletResponse response){
+ return service.login(user, response);
}
@PutMapping("/create")
@Operation(description = "创建用户", responses = {@ApiResponse(description = "返回创建后的用户")})
- public BaseResponse createUser(@RequestBody UserRegVo user){
- return service.createUser(user);
+ public BaseResponse createUser(@RequestBody UserRegVo user, HttpServletResponse response){
+ return service.createUser(user, response);
}
}
diff --git a/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java b/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java
index b63125b..1174fcb 100644
--- a/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java
+++ b/src/main/java/org/mmga/clubs/entities/user/UserLoginVo.java
@@ -1,4 +1,7 @@
package org.mmga.clubs.entities.user;
-public record UserLoginVo(String name, String password) {
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(description = "用户登录参数类")
+public record UserLoginVo(@Schema(description = "用户名") String username,@Schema(description = "用户密码(使用MD5摘要后的hex字符串)") String password) {
}
diff --git a/src/main/java/org/mmga/clubs/entities/user/UserRegVo.java b/src/main/java/org/mmga/clubs/entities/user/UserRegVo.java
index 2f3175b..8bc3033 100644
--- a/src/main/java/org/mmga/clubs/entities/user/UserRegVo.java
+++ b/src/main/java/org/mmga/clubs/entities/user/UserRegVo.java
@@ -1,4 +1,7 @@
package org.mmga.clubs.entities.user;
-public record UserRegVo(String username, String password, int auth) {
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(description = "用户注册参数")
+public record UserRegVo(@Schema(description = "用户名") String username,@Schema(description = "密码(使用MD5摘要后的hex字符串)") String password,@Schema(description = "用户的权限组ID") int auth) {
}
diff --git a/src/main/java/org/mmga/clubs/service/UserService.java b/src/main/java/org/mmga/clubs/service/UserService.java
index c24f631..c3373e4 100644
--- a/src/main/java/org/mmga/clubs/service/UserService.java
+++ b/src/main/java/org/mmga/clubs/service/UserService.java
@@ -1,9 +1,11 @@
package org.mmga.clubs.service;
+import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.codec.digest.DigestUtils;
import org.mmga.clubs.dao.UserDao;
import org.mmga.clubs.entities.BaseResponse;
import org.mmga.clubs.entities.user.*;
+import org.mmga.clubs.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -11,27 +13,36 @@ import org.springframework.stereotype.Service;
public class UserService {
private final UserDao userDao;
private final AuthService authService;
+ private final JwtUtils jwtUtils;
@Autowired
- public UserService(UserDao userDao, AuthService authService){
+ public UserService(UserDao userDao, AuthService authService, JwtUtils jwtUtils){
this.userDao = userDao;
this.authService = authService;
+ this.jwtUtils = jwtUtils;
}
- public BaseResponse login(UserLoginVo user) {
- UserVo userVo = userDao.getUser(user.name(), DigestUtils.sha1Hex(user.password()));
+ public BaseResponse login(UserLoginVo user, HttpServletResponse response) {
+ UserVo userVo = userDao.getUser(user.username(), DigestUtils.sha1Hex(user.password()));
User u = packageUser(userVo);
+ if (response != null && u != null){
+ response.addHeader("Set-Authorization", jwtUtils.createToken(u));
+ }
return u == null ? BaseResponse.failed(404, "无效用户") : BaseResponse.success(u);
}
- public BaseResponse createUser(UserRegVo user) {
+ public BaseResponse createUser(UserRegVo user, HttpServletResponse response) {
String username = user.username();
if (userDao.countUser(username) > 0) {
return BaseResponse.failed(409, "用户已存在");
}
- UserRegResponseVo response = new UserRegResponseVo(user);
- userDao.addUser(response);
- int newUserId = response.getId();
- return BaseResponse.success(packageUser(userDao.getUserById(newUserId)));
+ UserRegResponseVo responseVo = new UserRegResponseVo(user);
+ userDao.addUser(responseVo);
+ int newUserId = responseVo.getId();
+ User newUser = packageUser(userDao.getUserById(newUserId));
+ if (newUser != null && response != null) {
+ response.addHeader("Set-Authorization", jwtUtils.createToken(newUser));
+ }
+ return BaseResponse.success(newUser);
}
private User packageUser(UserVo vo) {
if (vo == null){
diff --git a/src/main/java/org/mmga/clubs/utils/JwtUtils.java b/src/main/java/org/mmga/clubs/utils/JwtUtils.java
index bbf54f1..b085014 100644
--- a/src/main/java/org/mmga/clubs/utils/JwtUtils.java
+++ b/src/main/java/org/mmga/clubs/utils/JwtUtils.java
@@ -1,8 +1,28 @@
package org.mmga.clubs.utils;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import lombok.extern.slf4j.Slf4j;
+import org.mmga.clubs.entities.user.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+
+@Component
+@Slf4j
public class JwtUtils {
- public static String createToken(int userId){
- //TODO 签名密钥创建
- return "";
+ private final ECPublicKey ecPublicKey;
+ private final ECPrivateKey ecPrivateKey;
+ @Autowired
+ public JwtUtils(ECPublicKey ecPublicKey, ECPrivateKey ecPrivateKey){
+ this.ecPublicKey = ecPublicKey;
+ this.ecPrivateKey = ecPrivateKey;
+ }
+ public String createToken(User user){
+ String jwt = JWT.create().withClaim("uid", user.getId()).sign(Algorithm.ECDSA512(ecPublicKey, ecPrivateKey));
+ log.debug("对用户:{},生成JWT:{}", user.getName(), jwt);
+ return jwt;
}
}
diff --git a/src/main/java/org/mmga/clubs/utils/ShellUtils.java b/src/main/java/org/mmga/clubs/utils/ShellUtils.java
index 886e8bf..5f3f4b5 100644
--- a/src/main/java/org/mmga/clubs/utils/ShellUtils.java
+++ b/src/main/java/org/mmga/clubs/utils/ShellUtils.java
@@ -2,7 +2,9 @@ package org.mmga.clubs.utils;
import org.mmga.clubs.entities.BaseResponse;
import org.slf4j.Logger;
+import org.springframework.stereotype.Component;
+@Component
public class ShellUtils {
public static void logToResult(Logger logger, BaseResponse> response){
logger.info("返回代码:{},返回信息:{}", response.getCode(), response.getMsg());
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index fa2059e..58de871 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,5 +1,2 @@
spring.application.name=ITZX-Clubs-Home-Server
-spring.datasource.url=jdbc:mysql://wzpmc.cn:3306/itzx
-spring.datasource.username=itzx
-spring.datasource.password=jdy53QFMm3yATQk3
springdoc.swagger-ui.path=/docs
\ No newline at end of file