新增后台管理系统(答辩用
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
wrapperVersion=3.3.4
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip
|
||||
@@ -0,0 +1,114 @@
|
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>gym-manage-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>gym-manage-cuit</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>gym-manage-cuit</name>
|
||||
<description>Auth Management Module</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer/>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection/>
|
||||
<developerConnection/>
|
||||
<tag/>
|
||||
<url/>
|
||||
</scm>
|
||||
<properties>
|
||||
<java.version>21</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>manage-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>manage-sys</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.novalon.gym.manage</groupId>
|
||||
<artifactId>manage-db</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations-jakarta</artifactId>
|
||||
<version>2.2.43</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Redis依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<!-- Spring Security -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package cn.novalon.gym.manage.auth.converter;
|
||||
|
||||
import cn.novalon.gym.manage.auth.domain.User;
|
||||
import cn.novalon.gym.manage.auth.dto.UserInfo;
|
||||
import cn.novalon.gym.manage.auth.entity.UserEntity;
|
||||
|
||||
public class UserConverter {
|
||||
|
||||
public static User toDomain(UserEntity entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
User user = new User();
|
||||
user.setId(entity.getId());
|
||||
user.setUsername(entity.getUsername());
|
||||
user.setEmail(entity.getEmail());
|
||||
user.setPhone(entity.getPhone());
|
||||
user.setNickname(entity.getNickname());
|
||||
user.setStatus(entity.getStatus());
|
||||
user.setRoleId(entity.getRoleId());
|
||||
user.setCreateBy(entity.getCreateBy());
|
||||
user.setUpdateBy(entity.getUpdateBy());
|
||||
user.setCreatedAt(entity.getCreatedAt());
|
||||
user.setUpdatedAt(entity.getUpdatedAt());
|
||||
user.setDeletedAt(entity.getDeletedAt());
|
||||
return user;
|
||||
}
|
||||
|
||||
public static UserEntity toEntity(User domain) {
|
||||
if (domain == null) {
|
||||
return null;
|
||||
}
|
||||
UserEntity entity = new UserEntity();
|
||||
entity.setId(domain.getId());
|
||||
entity.setUsername(domain.getUsername());
|
||||
entity.setEmail(domain.getEmail());
|
||||
entity.setPhone(domain.getPhone());
|
||||
entity.setNickname(domain.getNickname());
|
||||
entity.setStatus(domain.getStatus());
|
||||
entity.setRoleId(domain.getRoleId());
|
||||
entity.setCreateBy(domain.getCreateBy());
|
||||
entity.setUpdateBy(domain.getUpdateBy());
|
||||
entity.setCreatedAt(domain.getCreatedAt());
|
||||
entity.setUpdatedAt(domain.getUpdatedAt());
|
||||
entity.setDeletedAt(domain.getDeletedAt());
|
||||
return entity;
|
||||
}
|
||||
|
||||
public static UserInfo toUserInfo(User user) {
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
UserInfo userInfo = new UserInfo();
|
||||
userInfo.setId(user.getId());
|
||||
userInfo.setUsername(user.getUsername());
|
||||
userInfo.setEmail(user.getEmail());
|
||||
userInfo.setPhone(user.getPhone());
|
||||
userInfo.setNickname(user.getNickname());
|
||||
userInfo.setStatus(user.getStatus());
|
||||
userInfo.setRoleId(user.getRoleId());
|
||||
return userInfo;
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package cn.novalon.gym.manage.auth.dao;
|
||||
|
||||
import cn.novalon.gym.manage.auth.entity.UserEntity;
|
||||
import org.springframework.data.r2dbc.repository.Query;
|
||||
import org.springframework.data.r2dbc.repository.R2dbcRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Repository
|
||||
public interface UserDao extends R2dbcRepository<UserEntity, Long> {
|
||||
|
||||
@Query("SELECT * FROM sys_user WHERE username = :username AND deleted_at IS NULL")
|
||||
Mono<UserEntity> findByUsername(String username);
|
||||
|
||||
@Query("SELECT * FROM sys_user WHERE id = :id AND deleted_at IS NULL")
|
||||
Mono<UserEntity> findByIdAndDeletedAtIsNull(Long id);
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package cn.novalon.gym.manage.auth.domain;
|
||||
|
||||
import cn.novalon.gym.manage.sys.core.domain.BaseDomain;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
public class User extends BaseDomain {
|
||||
|
||||
@Schema(description = "用户名", example = "admin")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "邮箱", example = "admin@example.com")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "手机号", example = "13800138000")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "昵称", example = "超级管理员")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "状态:0-禁用,1-正常", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "角色ID", example = "1")
|
||||
private Long roleId;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public void setNickname(String nickname) {
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package cn.novalon.gym.manage.auth.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
@Schema(description = "用户登录请求")
|
||||
public class LoginRequest {
|
||||
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
@Schema(description = "用户名", example = "admin", required = true)
|
||||
private String username;
|
||||
|
||||
@NotBlank(message = "密码不能为空")
|
||||
@Schema(description = "密码", example = "Test@123", required = true)
|
||||
private String password;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package cn.novalon.gym.manage.auth.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
@Schema(description = "用户登录响应")
|
||||
public class LoginResponse {
|
||||
|
||||
@Schema(description = "访问令牌")
|
||||
private String accessToken;
|
||||
|
||||
@Schema(description = "刷新令牌")
|
||||
private String refreshToken;
|
||||
|
||||
@Schema(description = "令牌类型", example = "Bearer")
|
||||
private String tokenType;
|
||||
|
||||
@Schema(description = "过期时间(秒)", example = "7200")
|
||||
private Long expiresIn;
|
||||
|
||||
@Schema(description = "用户信息")
|
||||
private UserInfo userInfo;
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public String getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public void setRefreshToken(String refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
public void setTokenType(String tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
|
||||
public Long getExpiresIn() {
|
||||
return expiresIn;
|
||||
}
|
||||
|
||||
public void setExpiresIn(Long expiresIn) {
|
||||
this.expiresIn = expiresIn;
|
||||
}
|
||||
|
||||
public UserInfo getUserInfo() {
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
public void setUserInfo(UserInfo userInfo) {
|
||||
this.userInfo = userInfo;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package cn.novalon.gym.manage.auth.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
@Schema(description = "用户信息")
|
||||
public class UserInfo {
|
||||
|
||||
@Schema(description = "用户ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户名", example = "admin")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "邮箱", example = "admin@example.com")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "手机号", example = "13800138000")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "昵称", example = "超级管理员")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "状态:0-禁用,1-正常", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "角色ID", example = "1")
|
||||
private Long roleId;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public void setNickname(String nickname) {
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package cn.novalon.gym.manage.auth.entity;
|
||||
|
||||
import cn.novalon.gym.manage.db.entity.BaseEntity;
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
@Table("sys_user")
|
||||
public class UserEntity extends BaseEntity {
|
||||
|
||||
@Column("username")
|
||||
private String username;
|
||||
|
||||
@Column("password")
|
||||
private String password;
|
||||
|
||||
@Column("email")
|
||||
private String email;
|
||||
|
||||
@Column("phone")
|
||||
private String phone;
|
||||
|
||||
@Column("nickname")
|
||||
private String nickname;
|
||||
|
||||
@Column("status")
|
||||
private Integer status;
|
||||
|
||||
@Column("role_id")
|
||||
private Long roleId;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public void setNickname(String nickname) {
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package cn.novalon.gym.manage.auth.handler;
|
||||
|
||||
import cn.novalon.gym.manage.auth.dto.LoginRequest;
|
||||
import cn.novalon.gym.manage.auth.dto.LoginResponse;
|
||||
import cn.novalon.gym.manage.auth.dto.UserInfo;
|
||||
import cn.novalon.gym.manage.auth.service.IAuthService;
|
||||
import cn.novalon.gym.manage.auth.util.ResponseCode;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Validator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@Tag(name = "认证管理", description = "用户认证相关操作")
|
||||
public class AuthHandler {
|
||||
|
||||
private final IAuthService authService;
|
||||
private final Validator validator;
|
||||
|
||||
public AuthHandler(IAuthService authService, Validator validator) {
|
||||
this.authService = authService;
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
@Operation(summary = "用户名+密码登录", description = "使用用户名和密码进行登录认证")
|
||||
public Mono<ServerResponse> login(ServerRequest request) {
|
||||
return request.bodyToMono(LoginRequest.class)
|
||||
.flatMap(loginRequest -> {
|
||||
return authService.login(loginRequest)
|
||||
.flatMap(response -> {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", ResponseCode.SUCCESS);
|
||||
result.put("message", "登录成功");
|
||||
result.put("data", response);
|
||||
return ServerResponse.ok().bodyValue(result);
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
Map<String, Object> errorResponse = new HashMap<>();
|
||||
errorResponse.put("code", ResponseCode.BAD_REQUEST);
|
||||
errorResponse.put("message", error.getMessage());
|
||||
return ServerResponse.badRequest().bodyValue(errorResponse);
|
||||
});
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
Map<String, Object> errorResponse = new HashMap<>();
|
||||
errorResponse.put("code", ResponseCode.BAD_REQUEST);
|
||||
errorResponse.put("message", "请求参数错误: " + error.getMessage());
|
||||
return ServerResponse.badRequest().bodyValue(errorResponse);
|
||||
});
|
||||
}
|
||||
|
||||
@Operation(summary = "获取用户信息", description = "根据用户ID获取用户详细信息")
|
||||
public Mono<ServerResponse> getUserInfo(ServerRequest request) {
|
||||
try {
|
||||
Long userId = Long.valueOf(request.pathVariable("id"));
|
||||
return authService.getUserInfo(userId)
|
||||
.flatMap(userInfo -> {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", ResponseCode.SUCCESS);
|
||||
result.put("message", "获取用户信息成功");
|
||||
result.put("data", userInfo);
|
||||
return ServerResponse.ok().bodyValue(result);
|
||||
})
|
||||
.onErrorResume(error -> {
|
||||
Map<String, Object> errorResponse = new HashMap<>();
|
||||
errorResponse.put("code", ResponseCode.BAD_REQUEST);
|
||||
errorResponse.put("message", error.getMessage());
|
||||
return ServerResponse.badRequest().bodyValue(errorResponse);
|
||||
});
|
||||
} catch (NumberFormatException e) {
|
||||
Map<String, Object> errorResponse = new HashMap<>();
|
||||
errorResponse.put("code", ResponseCode.BAD_REQUEST);
|
||||
errorResponse.put("message", "无效的用户ID");
|
||||
return ServerResponse.badRequest().bodyValue(errorResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package cn.novalon.gym.manage.auth.repository;
|
||||
|
||||
import cn.novalon.gym.manage.auth.domain.User;
|
||||
import cn.novalon.gym.manage.auth.dto.LoginRequest;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface AuthRepository {
|
||||
|
||||
Mono<User> findByUsername(String username);
|
||||
|
||||
Mono<User> findById(Long id);
|
||||
|
||||
Mono<User> validateLogin(LoginRequest request);
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package cn.novalon.gym.manage.auth.repository.impl;
|
||||
|
||||
import cn.novalon.gym.manage.auth.converter.UserConverter;
|
||||
import cn.novalon.gym.manage.auth.dao.UserDao;
|
||||
import cn.novalon.gym.manage.auth.domain.User;
|
||||
import cn.novalon.gym.manage.auth.dto.LoginRequest;
|
||||
import cn.novalon.gym.manage.auth.repository.AuthRepository;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Component
|
||||
public class AuthRepositoryImpl implements AuthRepository {
|
||||
|
||||
private final UserDao userDao;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
public AuthRepositoryImpl(UserDao userDao, PasswordEncoder passwordEncoder) {
|
||||
this.userDao = userDao;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<User> findByUsername(String username) {
|
||||
return userDao.findByUsername(username)
|
||||
.map(UserConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<User> findById(Long id) {
|
||||
return userDao.findByIdAndDeletedAtIsNull(id)
|
||||
.map(UserConverter::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<User> validateLogin(LoginRequest request) {
|
||||
return userDao.findByUsername(request.getUsername())
|
||||
.flatMap(userEntity -> {
|
||||
if (userEntity.getStatus() == 0) {
|
||||
return Mono.error(new RuntimeException("用户已被禁用"));
|
||||
}
|
||||
if (passwordEncoder.matches(request.getPassword(), userEntity.getPassword())) {
|
||||
return Mono.just(UserConverter.toDomain(userEntity));
|
||||
} else {
|
||||
return Mono.error(new RuntimeException("用户名或密码错误"));
|
||||
}
|
||||
})
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("用户名或密码错误")));
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package cn.novalon.gym.manage.auth.service;
|
||||
|
||||
import cn.novalon.gym.manage.auth.dto.LoginRequest;
|
||||
import cn.novalon.gym.manage.auth.dto.LoginResponse;
|
||||
import cn.novalon.gym.manage.auth.dto.UserInfo;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface IAuthService {
|
||||
|
||||
Mono<LoginResponse> login(LoginRequest request);
|
||||
|
||||
Mono<UserInfo> getUserInfo(Long userId);
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package cn.novalon.gym.manage.auth.service.impl;
|
||||
|
||||
import cn.novalon.gym.manage.auth.converter.UserConverter;
|
||||
import cn.novalon.gym.manage.auth.dto.LoginRequest;
|
||||
import cn.novalon.gym.manage.auth.dto.LoginResponse;
|
||||
import cn.novalon.gym.manage.auth.dto.UserInfo;
|
||||
import cn.novalon.gym.manage.auth.repository.AuthRepository;
|
||||
import cn.novalon.gym.manage.auth.service.IAuthService;
|
||||
import cn.novalon.gym.manage.auth.util.JwtUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Service
|
||||
public class AuthServiceImpl implements IAuthService {
|
||||
|
||||
private final AuthRepository authRepository;
|
||||
private final JwtUtil jwtUtil;
|
||||
|
||||
public AuthServiceImpl(AuthRepository authRepository, JwtUtil jwtUtil) {
|
||||
this.authRepository = authRepository;
|
||||
this.jwtUtil = jwtUtil;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<LoginResponse> login(LoginRequest request) {
|
||||
return authRepository.validateLogin(request)
|
||||
.flatMap(user -> {
|
||||
String accessToken = jwtUtil.generateToken(user.getId(), user.getUsername());
|
||||
String refreshToken = jwtUtil.generateRefreshToken(user.getId(), user.getUsername());
|
||||
|
||||
LoginResponse response = new LoginResponse();
|
||||
response.setAccessToken(accessToken);
|
||||
response.setRefreshToken(refreshToken);
|
||||
response.setTokenType("Bearer");
|
||||
response.setExpiresIn(7200L);
|
||||
response.setUserInfo(UserConverter.toUserInfo(user));
|
||||
|
||||
return Mono.just(response);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<UserInfo> getUserInfo(Long userId) {
|
||||
return authRepository.findById(userId)
|
||||
.map(UserConverter::toUserInfo)
|
||||
.switchIfEmpty(Mono.error(new RuntimeException("用户不存在")));
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package cn.novalon.gym.manage.auth.util;
|
||||
|
||||
import cn.novalon.gym.manage.common.config.JwtProperties;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class JwtUtil {
|
||||
|
||||
private final JwtProperties jwtProperties;
|
||||
|
||||
public JwtUtil(JwtProperties jwtProperties) {
|
||||
this.jwtProperties = jwtProperties;
|
||||
}
|
||||
|
||||
private SecretKey getSigningKey() {
|
||||
return Keys.hmacShaKeyFor(jwtProperties.getSecret().getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public String generateToken(Long userId, String username) {
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put("userId", userId);
|
||||
claims.put("username", username);
|
||||
|
||||
return Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.setSubject(username)
|
||||
.setIssuedAt(new Date())
|
||||
.setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration()))
|
||||
.signWith(getSigningKey())
|
||||
.compact();
|
||||
}
|
||||
|
||||
public String generateRefreshToken(Long userId, String username) {
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put("userId", userId);
|
||||
claims.put("username", username);
|
||||
|
||||
return Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.setSubject(username + "_refresh")
|
||||
.setIssuedAt(new Date())
|
||||
.setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration() * 7))
|
||||
.signWith(getSigningKey())
|
||||
.compact();
|
||||
}
|
||||
|
||||
public Claims parseToken(String token) {
|
||||
return Jwts.parserBuilder()
|
||||
.setSigningKey(getSigningKey())
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
public Long getUserIdFromToken(String token) {
|
||||
return parseToken(token).get("userId", Long.class);
|
||||
}
|
||||
|
||||
public String getUsernameFromToken(String token) {
|
||||
return parseToken(token).getSubject();
|
||||
}
|
||||
|
||||
public boolean validateToken(String token) {
|
||||
try {
|
||||
parseToken(token);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package cn.novalon.gym.manage.auth.util;
|
||||
|
||||
/**
|
||||
* HTTP 响应状态码常量类
|
||||
*
|
||||
* @author 张翔
|
||||
* @date 2026-06-16
|
||||
*/
|
||||
public class ResponseCode {
|
||||
|
||||
private ResponseCode() {
|
||||
}
|
||||
|
||||
/** 成功 */
|
||||
public static final int SUCCESS = 200;
|
||||
|
||||
/** 客户端错误:请求参数有误 */
|
||||
public static final int BAD_REQUEST = 400;
|
||||
|
||||
/** 客户端错误:未授权 */
|
||||
public static final int UNAUTHORIZED = 401;
|
||||
|
||||
/** 客户端错误:禁止访问 */
|
||||
public static final int FORBIDDEN = 403;
|
||||
|
||||
/** 客户端错误:资源未找到 */
|
||||
public static final int NOT_FOUND = 404;
|
||||
|
||||
/** 客户端错误:冲突(如重复数据) */
|
||||
public static final int CONFLICT = 409;
|
||||
|
||||
/** 服务器错误:内部服务器错误 */
|
||||
public static final int INTERNAL_SERVER_ERROR = 500;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# JWT Configuration
|
||||
jwt:
|
||||
secret: mySecretKeyForJwtTokenGenerationThatIsLongEnoughForHS256Algorithm
|
||||
expiration: 7200 # 2 hours in seconds
|
||||
refresh-expiration: 604800 # 7 days in seconds
|
||||
|
||||
# Server Configuration
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
# Spring Configuration
|
||||
spring:
|
||||
application:
|
||||
name: gym-manage-cuit
|
||||
profiles:
|
||||
active: dev
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package cn.novalon.gym.manage.cuit.gymmanagecuit;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
@Disabled("模块无独立SpringBootApplication,需通过manage-app运行集成测试")
|
||||
class GymManageCuitApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user