feat(all): 添加了JWT相关功能
This commit is contained in:
parent
0902b2e1db
commit
e28467f3fa
2
.gitignore
vendored
2
.gitignore
vendored
@ -140,3 +140,5 @@ gradle-app.setting
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
# Running
|
||||
run/
|
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="IncorrectHttpHeaderInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="customHeaders">
|
||||
<set>
|
||||
<option value="Set-Authorization" />
|
||||
</set>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
1
.idea/modules.xml
generated
1
.idea/modules.xml
generated
@ -2,6 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/clubs.iml" filepath="$PROJECT_DIR$/.idea/modules/clubs.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/clubs.main.iml" filepath="$PROJECT_DIR$/.idea/modules/clubs.main.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
|
10
.idea/modules/clubs.iml
generated
Normal file
10
.idea/modules/clubs.iml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="AdditionalModuleElements">
|
||||
<content url="file://$MODULE_DIR$/../.." dumb="true">
|
||||
<excludeFolder url="file://$MODULE_DIR$/../dataSources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../dictionaries" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../run" />
|
||||
</content>
|
||||
</component>
|
||||
</module>
|
@ -20,12 +20,12 @@ public class UserCommands {
|
||||
}
|
||||
@ShellMethod("创建用户")
|
||||
public void createUser(String name, String password) {
|
||||
BaseResponse<User> user = this.userController.createUser(new UserRegVo(name, DigestUtils.md5Hex(password), 1));
|
||||
BaseResponse<User> 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> user = this.userController.login(new UserLoginVo(name, DigestUtils.md5Hex(password)));
|
||||
BaseResponse<User> user = this.userController.login(new UserLoginVo(name, DigestUtils.md5Hex(password)), null);
|
||||
ShellUtils.logToResult(log, user);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<User> login(@RequestBody UserLoginVo user){
|
||||
return service.login(user);
|
||||
public BaseResponse<User> login(@RequestBody UserLoginVo user, HttpServletResponse response){
|
||||
return service.login(user, response);
|
||||
}
|
||||
@PutMapping("/create")
|
||||
@Operation(description = "创建用户", responses = {@ApiResponse(description = "返回创建后的用户")})
|
||||
public BaseResponse<User> createUser(@RequestBody UserRegVo user){
|
||||
return service.createUser(user);
|
||||
public BaseResponse<User> createUser(@RequestBody UserRegVo user, HttpServletResponse response){
|
||||
return service.createUser(user, response);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
|
@ -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<User> login(UserLoginVo user) {
|
||||
UserVo userVo = userDao.getUser(user.name(), DigestUtils.sha1Hex(user.password()));
|
||||
public BaseResponse<User> 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<User> createUser(UserRegVo user) {
|
||||
public BaseResponse<User> 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){
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user