refactor: 拆分出认证服务
This commit is contained in:
1
.idea/encodings.xml
generated
1
.idea/encodings.xml
generated
@@ -3,6 +3,7 @@
|
|||||||
<component name="Encoding">
|
<component name="Encoding">
|
||||||
<file url="file://$PROJECT_DIR$/aioj-backend-ai-service/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/aioj-backend-ai-service/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/aioj-backend-ai-service/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/aioj-backend-ai-service/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/aioj-backend-auth/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/aioj-backend-client/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/aioj-backend-client/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/aioj-backend-client/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/aioj-backend-client/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/aioj-backend-common/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/aioj-backend-common/src/main/java" charset="UTF-8" />
|
||||||
|
|||||||
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@@ -7,6 +7,11 @@
|
|||||||
<option value="$PROJECT_DIR$/pom.xml" />
|
<option value="$PROJECT_DIR$/pom.xml" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="ignoredFiles">
|
||||||
|
<set>
|
||||||
|
<option value="$PROJECT_DIR$/aioj-backend-model/pom.xml" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="zulu-17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="zulu-17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
|||||||
100
aioj-backend-auth/pom.xml
Normal file
100
aioj-backend-auth/pom.xml
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<?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>cn.meowrain</groupId>
|
||||||
|
<artifactId>ai-oj</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>aioj-backend-auth</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- spring cloud发现服务-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- OAuth2 Client -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Spring Security -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--JWT-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-api</artifactId>
|
||||||
|
<version>0.13.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-impl</artifactId>
|
||||||
|
<version>0.13.0</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
|
<version>0.13.0</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--
|
||||||
|
引用通用模块
|
||||||
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.meowrain</groupId>
|
||||||
|
<artifactId>aioj-backend-common</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<!--引入openfeign-->
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
|
<version>4.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||||
|
<version>4.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
|
|
||||||
|
@EnableFeignClients(basePackages = "cn.meowrain.aioj.backend.auth.clients")
|
||||||
|
@SpringBootApplication
|
||||||
|
public class AIOJAuthApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(AIOJAuthApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth.clients;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.resp.UserAuthRespDTO;
|
||||||
|
import cn.meowrain.aioj.backend.framework.web.Result;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
@FeignClient(name = "user-service", path = "/api/v1/user")
|
||||||
|
public interface UserClient {
|
||||||
|
@GetMapping("/inner/get-by-username")
|
||||||
|
Result<UserAuthRespDTO> getUserByUserName(@RequestParam("userAccount") String userAccount);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth.common.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum ChainMarkEnums {
|
||||||
|
/**
|
||||||
|
* 用户登录请求验证
|
||||||
|
*/
|
||||||
|
USER_LOGIN_REQ_PARAM_VERIFY("USER_LOGIN_REQ_PARAM_VERIFY");
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final String markName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return markName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.config;
|
package cn.meowrain.aioj.backend.auth.config;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.config;
|
package cn.meowrain.aioj.backend.auth.config;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@@ -10,18 +10,10 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
|||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
||||||
|
|
||||||
import cn.meowrain.aioj.backend.userservice.security.JwtAuthenticationFilter;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class SecurityConfiguration {
|
public class SecurityConfiguration {
|
||||||
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
|
||||||
|
|
||||||
public SecurityConfiguration(JwtAuthenticationFilter jwtAuthenticationFilter) {
|
|
||||||
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
@@ -30,7 +22,7 @@ public class SecurityConfiguration {
|
|||||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
.requestMatchers(
|
.requestMatchers(
|
||||||
"/auth/**",
|
"/v1/auth/**",
|
||||||
"/doc.html",
|
"/doc.html",
|
||||||
"/swagger-ui/**",
|
"/swagger-ui/**",
|
||||||
"/swagger-resources/**",
|
"/swagger-resources/**",
|
||||||
@@ -39,8 +31,7 @@ public class SecurityConfiguration {
|
|||||||
"/favicon.ico"
|
"/favicon.ico"
|
||||||
)
|
)
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.anyRequest().authenticated())
|
.anyRequest().authenticated());
|
||||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth.config;
|
||||||
|
|
||||||
|
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
|
||||||
|
import io.swagger.v3.oas.models.OpenAPI;
|
||||||
|
import io.swagger.v3.oas.models.info.Contact;
|
||||||
|
import io.swagger.v3.oas.models.info.Info;
|
||||||
|
import io.swagger.v3.oas.models.info.License;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.ApplicationArguments;
|
||||||
|
import org.springframework.boot.ApplicationRunner;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
@EnableKnife4j
|
||||||
|
public class SwaggerConfiguration implements ApplicationRunner {
|
||||||
|
@Value("${server.port:8080}")
|
||||||
|
private String serverPort;
|
||||||
|
@Value("${server.servlet.context-path:}")
|
||||||
|
private String contextPath;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public OpenAPI customerOpenAPI() {
|
||||||
|
return new OpenAPI()
|
||||||
|
.info(new Info()
|
||||||
|
.title("AIOJ-renz微服务✨")
|
||||||
|
.description("用户认证功能")
|
||||||
|
.version("v1.0.0")
|
||||||
|
.contact(new Contact().name("meowrain").email("meowrain@126.com"))
|
||||||
|
.license(new License().name("MeowRain").url("https://meowrain.cn")));
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
|
log.info("✨API Document: http://127.0.0.1:{}{}/doc.html", serverPort, contextPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth.controller;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.req.UserLoginRequestDTO;
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.resp.UserLoginResponseDTO;
|
||||||
|
import cn.meowrain.aioj.backend.auth.service.AuthService;
|
||||||
|
import cn.meowrain.aioj.backend.framework.web.Results;
|
||||||
|
import cn.meowrain.aioj.backend.framework.web.Result;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/v1/auth")
|
||||||
|
public class AuthController {
|
||||||
|
|
||||||
|
private final AuthService authService;
|
||||||
|
|
||||||
|
public AuthController(AuthService authService) {
|
||||||
|
this.authService = authService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/login")
|
||||||
|
public Result<UserLoginResponseDTO> login(@RequestBody UserLoginRequestDTO userLoginRequest) {
|
||||||
|
UserLoginResponseDTO userLoginResponse = authService.userLogin(userLoginRequest);
|
||||||
|
return Results.success(userLoginResponse);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/auth")
|
||||||
|
public Result<String> auth(@RequestBody UserLoginRequestDTO userLoginRequest) {
|
||||||
|
UserLoginResponseDTO userLoginResponseDTO = authService.userLogin(userLoginRequest);
|
||||||
|
return Results.success(userLoginResponseDTO.getToken());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.dto.chains;
|
package cn.meowrain.aioj.backend.auth.dto.chains;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.auth.common.enums.ChainMarkEnums;
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.req.UserLoginRequestDTO;
|
||||||
import cn.meowrain.aioj.backend.framework.designpattern.chains.AbstractChianHandler;
|
import cn.meowrain.aioj.backend.framework.designpattern.chains.AbstractChianHandler;
|
||||||
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
||||||
import cn.meowrain.aioj.backend.framework.exception.ClientException;
|
import cn.meowrain.aioj.backend.framework.exception.ClientException;
|
||||||
import cn.meowrain.aioj.backend.userservice.common.enums.ChainMarkEnums;
|
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserLoginRequest;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class UserLoginRequestParamVerifyChain implements AbstractChianHandler<UserLoginRequest> {
|
public class UserLoginRequestParamVerifyChain implements AbstractChianHandler<UserLoginRequestDTO> {
|
||||||
@Override
|
@Override
|
||||||
public void handle(UserLoginRequest requestParam) {
|
public void handle(UserLoginRequestDTO requestParam) {
|
||||||
if (StringUtils.isAnyBlank(requestParam.getUserAccount(), requestParam.getUserPassword())) {
|
if (StringUtils.isAnyBlank(requestParam.getUserAccount(), requestParam.getUserPassword())) {
|
||||||
throw new ClientException("参数为空", ErrorCode.PARAMS_ERROR);
|
throw new ClientException("参数为空", ErrorCode.PARAMS_ERROR);
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.dto.chains.context;
|
package cn.meowrain.aioj.backend.auth.dto.chains.context;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.req.UserLoginRequestDTO;
|
||||||
import cn.meowrain.aioj.backend.framework.designpattern.chains.CommonChainContext;
|
import cn.meowrain.aioj.backend.framework.designpattern.chains.CommonChainContext;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserLoginRequest;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class UserLoginRequestParamVerifyContext extends CommonChainContext<UserLoginRequest> {
|
public class UserLoginRequestParamVerifyContext extends CommonChainContext<UserLoginRequestDTO> {
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth.dto.req;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserLoginRequestDTO {
|
||||||
|
private String userAccount;
|
||||||
|
private String userPassword;
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth.dto.resp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户认证响应体
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserAuthRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户账号
|
||||||
|
*/
|
||||||
|
private String userAccount;
|
||||||
|
/**
|
||||||
|
* 用户密码
|
||||||
|
*/
|
||||||
|
private String userPassword;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开放平台id
|
||||||
|
*/
|
||||||
|
private String unionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公众号openId
|
||||||
|
*/
|
||||||
|
private String mpOpenId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户昵称
|
||||||
|
*/
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户头像
|
||||||
|
*/
|
||||||
|
private String userAvatar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户简介
|
||||||
|
*/
|
||||||
|
private String userProfile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户角色:user/admin/ban
|
||||||
|
*/
|
||||||
|
private String userRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth.dto.resp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserLoginResponseDTO implements Serializable {
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户账号
|
||||||
|
*/
|
||||||
|
private String userAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开放平台id
|
||||||
|
*/
|
||||||
|
private String unionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公众号openId
|
||||||
|
*/
|
||||||
|
private String mpOpenId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户昵称
|
||||||
|
*/
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户头像
|
||||||
|
*/
|
||||||
|
private String userAvatar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户简介
|
||||||
|
*/
|
||||||
|
private String userProfile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户角色:user/admin/ban
|
||||||
|
*/
|
||||||
|
private String userRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否删除
|
||||||
|
*/
|
||||||
|
|
||||||
|
private Integer isDelete;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JWT令牌(登录成功返回)
|
||||||
|
*/
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth.service;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.req.UserLoginRequestDTO;
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.resp.UserLoginResponseDTO;
|
||||||
|
|
||||||
|
public interface AuthService {
|
||||||
|
/**
|
||||||
|
* 用户登录
|
||||||
|
* @param request {@link UserLoginRequestDTO}
|
||||||
|
* @return {@link UserLoginResponseDTO}
|
||||||
|
*/
|
||||||
|
UserLoginResponseDTO userLogin(UserLoginRequestDTO request);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package cn.meowrain.aioj.backend.auth.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.crypto.digest.BCrypt;
|
||||||
|
import cn.meowrain.aioj.backend.auth.clients.UserClient;
|
||||||
|
import cn.meowrain.aioj.backend.auth.common.enums.ChainMarkEnums;
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.chains.context.UserLoginRequestParamVerifyContext;
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.req.UserLoginRequestDTO;
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.resp.UserAuthRespDTO;
|
||||||
|
import cn.meowrain.aioj.backend.auth.dto.resp.UserLoginResponseDTO;
|
||||||
|
import cn.meowrain.aioj.backend.auth.service.AuthService;
|
||||||
|
import cn.meowrain.aioj.backend.auth.utils.JwtUtil;
|
||||||
|
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
||||||
|
import cn.meowrain.aioj.backend.framework.exception.ServiceException;
|
||||||
|
import cn.meowrain.aioj.backend.framework.web.Result;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class AuthServiceImpl implements AuthService {
|
||||||
|
private final JwtUtil jwtUtil;
|
||||||
|
private final UserLoginRequestParamVerifyContext userLoginRequestParamVerifyContext;
|
||||||
|
private final UserClient userClient;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserLoginResponseDTO userLogin(UserLoginRequestDTO requestParam) {
|
||||||
|
// 1.校验
|
||||||
|
userLoginRequestParamVerifyContext.handler(ChainMarkEnums.USER_LOGIN_REQ_PARAM_VERIFY.getMarkName(),
|
||||||
|
requestParam);
|
||||||
|
// 如果调用user-service失败,那么就说明是系统内部错误
|
||||||
|
Result<UserAuthRespDTO> userResp = userClient.getUserByUserName(requestParam.getUserAccount());
|
||||||
|
if (userResp.isFail()) {
|
||||||
|
log.error("调用user-service返回失败:{}", userResp.getMessage());
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR);
|
||||||
|
}
|
||||||
|
UserAuthRespDTO user = userResp.getData();
|
||||||
|
|
||||||
|
if (ObjectUtil.isNull(user)
|
||||||
|
|| !BCrypt.checkpw(requestParam.getUserPassword(), user.getUserPassword())) {
|
||||||
|
throw new ServiceException("用户不存在或者密码错误", ErrorCode.NOT_LOGIN_ERROR);
|
||||||
|
}
|
||||||
|
// 生成 JWT
|
||||||
|
String token = jwtUtil.generateToken(user);
|
||||||
|
UserLoginResponseDTO resp = new UserLoginResponseDTO();
|
||||||
|
resp.setId(user.getId());
|
||||||
|
resp.setUserAccount(user.getUserAccount());
|
||||||
|
resp.setUserAvatar(user.getUserAvatar());
|
||||||
|
resp.setUserProfile(user.getUserProfile());
|
||||||
|
resp.setUserRole(user.getUserRole());
|
||||||
|
resp.setCreateTime(user.getCreateTime());
|
||||||
|
resp.setUpdateTime(user.getUpdateTime());
|
||||||
|
resp.setToken(token);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.utils;
|
package cn.meowrain.aioj.backend.auth.utils;
|
||||||
|
|
||||||
import cn.meowrain.aioj.backend.userservice.config.JwtPropertiesConfiguration;
|
import cn.meowrain.aioj.backend.auth.config.JwtPropertiesConfiguration;
|
||||||
import cn.meowrain.aioj.backend.userservice.dao.entity.User;
|
import cn.meowrain.aioj.backend.auth.dto.resp.UserAuthRespDTO;
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
import io.jsonwebtoken.security.Keys;
|
import io.jsonwebtoken.security.Keys;
|
||||||
@@ -25,7 +25,7 @@ public class JwtUtil {
|
|||||||
return Keys.hmacShaKeyFor(jwtConfig.getSecret().getBytes());
|
return Keys.hmacShaKeyFor(jwtConfig.getSecret().getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateToken(User user) {
|
public String generateToken(UserAuthRespDTO user) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Map<String, Object> claims = new HashMap<>();
|
Map<String, Object> claims = new HashMap<>();
|
||||||
claims.put("userId", user.getId());
|
claims.put("userId", user.getId());
|
||||||
9
aioj-backend-auth/src/main/resources/application-dev.yml
Normal file
9
aioj-backend-auth/src/main/resources/application-dev.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
spring:
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
enabled: true
|
||||||
|
register-enabled: true
|
||||||
|
server-addr: 10.0.0.10:8848
|
||||||
|
username: nacos
|
||||||
|
password: nacos
|
||||||
37
aioj-backend-auth/src/main/resources/application.yml
Normal file
37
aioj-backend-auth/src/main/resources/application.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: auth-service
|
||||||
|
profiles:
|
||||||
|
active: @env@
|
||||||
|
devtools:
|
||||||
|
livereload:
|
||||||
|
enabled: true
|
||||||
|
server:
|
||||||
|
port: 10011
|
||||||
|
servlet:
|
||||||
|
context-path: /api
|
||||||
|
springdoc:
|
||||||
|
api-docs:
|
||||||
|
enabled: true
|
||||||
|
path: /v3/api-docs
|
||||||
|
default-flat-param-object: true
|
||||||
|
swagger-ui:
|
||||||
|
path: /swagger-ui.html
|
||||||
|
tags-sorter: alpha
|
||||||
|
operations-sorter: alpha
|
||||||
|
group-configs:
|
||||||
|
- group: 'default'
|
||||||
|
paths-to-match: '/**'
|
||||||
|
packages-to-scan: cn.meowrain.aioj.backend.userservice.controller
|
||||||
|
knife4j:
|
||||||
|
basic:
|
||||||
|
enable: true
|
||||||
|
setting:
|
||||||
|
language: zh_cn
|
||||||
|
mybatis-plus:
|
||||||
|
configuration:
|
||||||
|
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||||
|
mapper-locations: classpath*:/mapper/**/*.xml
|
||||||
|
jwt:
|
||||||
|
secret: "12345678901234567890123456789012" # 至少32字节!!
|
||||||
|
expire: 86400000 # 24小时(单位:毫秒)
|
||||||
@@ -41,5 +41,14 @@
|
|||||||
<groupId>com.alibaba.cloud</groupId>
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-extension</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
spring:
|
||||||
|
data:
|
||||||
|
redis:
|
||||||
|
host: 10.0.0.10
|
||||||
|
port: 6379
|
||||||
|
password: 123456
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
enabled: true
|
||||||
|
register-enabled: true
|
||||||
|
server-addr: 10.0.0.10:8848
|
||||||
|
username: nacos
|
||||||
|
password: nacos
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<?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>cn.meowrain</groupId>
|
|
||||||
<artifactId>ai-oj</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<artifactId>aioj-backend-model</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
|
||||||
<maven.compiler.target>17</maven.compiler.target>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@@ -32,17 +32,6 @@
|
|||||||
<artifactId>aioj-backend-common</artifactId>
|
<artifactId>aioj-backend-common</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Spring Security -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-security</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- OAuth2 Client -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
@@ -81,23 +70,5 @@
|
|||||||
<groupId>com.alibaba.cloud</groupId>
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--JWT-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-api</artifactId>
|
|
||||||
<version>0.13.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-impl</artifactId>
|
|
||||||
<version>0.13.0</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-jackson</artifactId>
|
|
||||||
<version>0.13.0</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.config;
|
package cn.meowrain.aioj.backend.userservice.config;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.ComponentScans;
|
import org.springframework.context.annotation.ComponentScans;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|||||||
@@ -2,35 +2,31 @@ package cn.meowrain.aioj.backend.userservice.controller;
|
|||||||
|
|
||||||
import cn.meowrain.aioj.backend.framework.web.Result;
|
import cn.meowrain.aioj.backend.framework.web.Result;
|
||||||
import cn.meowrain.aioj.backend.framework.web.Results;
|
import cn.meowrain.aioj.backend.framework.web.Results;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserLoginRequest;
|
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequest;
|
import cn.meowrain.aioj.backend.userservice.dto.resp.UserAuthRespDTO;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.resp.UserLoginResponse;
|
|
||||||
import cn.meowrain.aioj.backend.userservice.service.UserService;
|
import cn.meowrain.aioj.backend.userservice.service.UserService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RestController()
|
@RestController()
|
||||||
@RequestMapping("/auth")
|
@RequestMapping("/v1/user")
|
||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
public Result<Long> register(@RequestBody UserRegisterRequest userRegisterRequest) {
|
public Result<Long> register(@RequestBody UserRegisterRequestDTO userRegisterRequest) {
|
||||||
Long l = userService.userRegister(userRegisterRequest);
|
Long l = userService.userRegister(userRegisterRequest);
|
||||||
return Results.success(l);
|
return Results.success(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/login")
|
@GetMapping("/inner/get-by-username")
|
||||||
public Result<UserLoginResponse> login(@RequestBody UserLoginRequest userLoginRequest) {
|
public Result<UserAuthRespDTO> getUserByUserName(@RequestParam("userAccount") String userAccount) {
|
||||||
UserLoginResponse userLoginResponse = userService.userLogin(userLoginRequest);
|
UserAuthRespDTO userAuthDTO = userService.findAuthInfoByUserAccount(userAccount);
|
||||||
return Results.success(userLoginResponse);
|
return Results.success(userAuthDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ import cn.meowrain.aioj.backend.framework.designpattern.chains.AbstractChianHand
|
|||||||
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
||||||
import cn.meowrain.aioj.backend.framework.exception.ClientException;
|
import cn.meowrain.aioj.backend.framework.exception.ClientException;
|
||||||
import cn.meowrain.aioj.backend.userservice.common.enums.ChainMarkEnums;
|
import cn.meowrain.aioj.backend.userservice.common.enums.ChainMarkEnums;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequest;
|
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class UserRegisterRequestParamVerifyChain implements AbstractChianHandler<UserRegisterRequest> {
|
public class UserRegisterRequestParamVerifyChain implements AbstractChianHandler<UserRegisterRequestDTO> {
|
||||||
@Override
|
@Override
|
||||||
public void handle(UserRegisterRequest requestParam) {
|
public void handle(UserRegisterRequestDTO requestParam) {
|
||||||
// 校验参数里面用户名和密码是不是空的
|
// 校验参数里面用户名和密码是不是空的
|
||||||
if (StringUtils.isAnyBlank(requestParam.getUserAccount(), requestParam.getUserPassword())) {
|
if (StringUtils.isAnyBlank(requestParam.getUserAccount(), requestParam.getUserPassword())) {
|
||||||
throw new ClientException("参数为空", ErrorCode.PARAMS_ERROR);
|
throw new ClientException("参数为空", ErrorCode.PARAMS_ERROR);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.dto.chains.context;
|
package cn.meowrain.aioj.backend.userservice.dto.chains.context;
|
||||||
|
|
||||||
import cn.meowrain.aioj.backend.framework.designpattern.chains.CommonChainContext;
|
import cn.meowrain.aioj.backend.framework.designpattern.chains.CommonChainContext;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequest;
|
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class UserRegisterRequestParamVerifyContext extends CommonChainContext<UserRegisterRequest> {
|
public class UserRegisterRequestParamVerifyContext extends CommonChainContext<UserRegisterRequestDTO> {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class UserLoginRequest {
|
public class UserLoginRequestDTO {
|
||||||
private String userAccount;
|
private String userAccount;
|
||||||
private String userPassword;
|
private String userPassword;
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class UserRegisterRequest {
|
public class UserRegisterRequestDTO {
|
||||||
private String userAccount;
|
private String userAccount;
|
||||||
private String userPassword;
|
private String userPassword;
|
||||||
private String checkPassword;
|
private String checkPassword;
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package cn.meowrain.aioj.backend.userservice.dto.resp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户认证响应体
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserAuthRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户账号
|
||||||
|
*/
|
||||||
|
private String userAccount;
|
||||||
|
/**
|
||||||
|
* 用户密码
|
||||||
|
*/
|
||||||
|
private String userPassword;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开放平台id
|
||||||
|
*/
|
||||||
|
private String unionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公众号openId
|
||||||
|
*/
|
||||||
|
private String mpOpenId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户昵称
|
||||||
|
*/
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户头像
|
||||||
|
*/
|
||||||
|
private String userAvatar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户简介
|
||||||
|
*/
|
||||||
|
private String userProfile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户角色:user/admin/ban
|
||||||
|
*/
|
||||||
|
private String userRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import java.io.Serializable;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class UserLoginResponse implements Serializable {
|
public class UserLoginResponseDTO implements Serializable {
|
||||||
/**
|
/**
|
||||||
* id
|
* id
|
||||||
*/
|
*/
|
||||||
@@ -8,6 +8,6 @@ import java.io.Serializable;
|
|||||||
* 用户注册成功响应对象
|
* 用户注册成功响应对象
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class UserRegisterResponse implements Serializable {
|
public class UserRegisterResponseDTO implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
}
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.security;
|
|
||||||
|
|
||||||
import cn.meowrain.aioj.backend.userservice.dao.entity.User;
|
|
||||||
import cn.meowrain.aioj.backend.userservice.dao.mapper.UserMapper;
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class CustomUserDetailsService implements UserDetailsService {
|
|
||||||
private final UserMapper userMapper;
|
|
||||||
|
|
||||||
public CustomUserDetailsService(UserMapper userMapper) {
|
|
||||||
this.userMapper = userMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
|
||||||
User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUserAccount, username));
|
|
||||||
if (user == null) {
|
|
||||||
throw new UsernameNotFoundException("用户不存在: " + username);
|
|
||||||
}
|
|
||||||
Collection<? extends GrantedAuthority> authorities = Collections
|
|
||||||
.singletonList(new SimpleGrantedAuthority(user.getUserRole()));
|
|
||||||
return new org.springframework.security.core.userdetails.User(user.getUserAccount(), user.getUserPassword(),
|
|
||||||
authorities);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.security;
|
|
||||||
|
|
||||||
import cn.meowrain.aioj.backend.userservice.dao.entity.User;
|
|
||||||
import cn.meowrain.aioj.backend.userservice.dao.mapper.UserMapper;
|
|
||||||
import cn.meowrain.aioj.backend.userservice.utils.JwtUtil;
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
import jakarta.servlet.FilterChain;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JWT请求过滤器:解析 Authorization 头中的 Bearer token 并设置认证上下文
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
||||||
|
|
||||||
private final JwtUtil jwtUtil;
|
|
||||||
private final UserMapper userMapper;
|
|
||||||
|
|
||||||
public JwtAuthenticationFilter(JwtUtil jwtUtil, UserMapper userMapper) {
|
|
||||||
this.jwtUtil = jwtUtil;
|
|
||||||
this.userMapper = userMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(HttpServletRequest request,
|
|
||||||
HttpServletResponse response,
|
|
||||||
FilterChain filterChain) throws ServletException, IOException {
|
|
||||||
String header = request.getHeader("Authorization");
|
|
||||||
if (!StringUtils.hasText(header) || !header.startsWith("Bearer ")) {
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String token = header.substring(7);
|
|
||||||
if (!jwtUtil.isTokenValid(token)) {
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Claims claims = jwtUtil.parseClaims(token);
|
|
||||||
String account = claims.getSubject();
|
|
||||||
Long userId = claims.get("userId", Long.class);
|
|
||||||
|
|
||||||
// 避免重复设置
|
|
||||||
if (StringUtils.hasText(account) && SecurityContextHolder.getContext().getAuthentication() == null) {
|
|
||||||
// 可选:从数据库再查一次,保证用户未被删除/封禁
|
|
||||||
User user = userMapper.selectById(userId);
|
|
||||||
if (user == null || !StringUtils.hasText(user.getUserRole())) {
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<SimpleGrantedAuthority> authorities = Collections
|
|
||||||
.singletonList(new SimpleGrantedAuthority(user.getUserRole()));
|
|
||||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(account,
|
|
||||||
null, authorities);
|
|
||||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
// 解析失败直接继续,不抛出,保持无状态
|
|
||||||
}
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +1,25 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.service;
|
package cn.meowrain.aioj.backend.userservice.service;
|
||||||
|
|
||||||
import cn.meowrain.aioj.backend.userservice.dao.entity.User;
|
import cn.meowrain.aioj.backend.userservice.dao.entity.User;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserLoginRequest;
|
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequest;
|
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.resp.UserLoginResponse;
|
import cn.meowrain.aioj.backend.userservice.dto.resp.UserAuthRespDTO;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
public interface UserService extends IService<User> {
|
public interface UserService extends IService<User> {
|
||||||
/**
|
/**
|
||||||
* 用户注册
|
* 用户注册
|
||||||
* @param request {@link UserRegisterRequest}
|
* @param request {@link cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO}
|
||||||
* @return {@link Long}
|
* @return {@link Long}
|
||||||
*/
|
*/
|
||||||
Long userRegister(UserRegisterRequest request);
|
Long userRegister(UserRegisterRequestDTO request);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户登录
|
* 根据用户账号查找用户认证信息
|
||||||
* @param request {@link UserLoginRequest}
|
* @param userAccount
|
||||||
* @return {@link UserLoginResponse}
|
* @return
|
||||||
*/
|
*/
|
||||||
UserLoginResponse userLogin(UserLoginRequest request);
|
UserAuthRespDTO findAuthInfoByUserAccount(String userAccount);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,48 @@
|
|||||||
package cn.meowrain.aioj.backend.userservice.service.impl;
|
package cn.meowrain.aioj.backend.userservice.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.crypto.digest.BCrypt;
|
||||||
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
||||||
|
import cn.meowrain.aioj.backend.framework.exception.ClientException;
|
||||||
import cn.meowrain.aioj.backend.framework.exception.ServiceException;
|
import cn.meowrain.aioj.backend.framework.exception.ServiceException;
|
||||||
import cn.meowrain.aioj.backend.userservice.common.enums.ChainMarkEnums;
|
import cn.meowrain.aioj.backend.userservice.common.enums.ChainMarkEnums;
|
||||||
import cn.meowrain.aioj.backend.userservice.dao.entity.User;
|
import cn.meowrain.aioj.backend.userservice.dao.entity.User;
|
||||||
import cn.meowrain.aioj.backend.userservice.dao.mapper.UserMapper;
|
import cn.meowrain.aioj.backend.userservice.dao.mapper.UserMapper;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.chains.context.UserLoginRequestParamVerifyContext;
|
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.chains.context.UserRegisterRequestParamVerifyContext;
|
import cn.meowrain.aioj.backend.userservice.dto.chains.context.UserRegisterRequestParamVerifyContext;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserLoginRequest;
|
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequest;
|
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO;
|
||||||
import cn.meowrain.aioj.backend.userservice.dto.resp.UserLoginResponse;
|
import cn.meowrain.aioj.backend.userservice.dto.resp.UserAuthRespDTO;
|
||||||
import cn.meowrain.aioj.backend.userservice.service.UserService;
|
import cn.meowrain.aioj.backend.userservice.service.UserService;
|
||||||
import cn.meowrain.aioj.backend.userservice.utils.JwtUtil;
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
|
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
|
||||||
private final UserRegisterRequestParamVerifyContext userRegisterRequestParamVerifyContext;
|
private final UserRegisterRequestParamVerifyContext userRegisterRequestParamVerifyContext;
|
||||||
private final UserLoginRequestParamVerifyContext userLoginRequestParamVerifyContext;
|
|
||||||
private final PasswordEncoder passwordEncoder;
|
|
||||||
private final JwtUtil jwtUtil;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long userRegister(UserRegisterRequest request) {
|
public Long userRegister(UserRegisterRequestDTO request) {
|
||||||
|
UserAuthRespDTO authInfoByUserAccount = findAuthInfoByUserAccount(request.getUserAccount());
|
||||||
|
if(authInfoByUserAccount!=null){
|
||||||
|
throw new ClientException("重复创建用户");
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("进行用户注册");
|
||||||
userRegisterRequestParamVerifyContext.handler(ChainMarkEnums.USER_REGISTER_REQ_PARAM_VERIFY.getMarkName(),
|
userRegisterRequestParamVerifyContext.handler(ChainMarkEnums.USER_REGISTER_REQ_PARAM_VERIFY.getMarkName(),
|
||||||
request);
|
request);
|
||||||
// 使用 BCrypt 加密密码
|
// 使用 BCrypt 加密密码
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
String encryptPassword = passwordEncoder.encode(request.getUserPassword());
|
String salt = BCrypt.gensalt();
|
||||||
|
String encryptPassword = BCrypt.hashpw(request.getUserPassword(),salt);
|
||||||
User user = new User().setUserAccount(request.getUserAccount()).setUserPassword(encryptPassword)
|
User user = new User().setUserAccount(request.getUserAccount()).setUserPassword(encryptPassword)
|
||||||
.setUserRole("user").setCreateTime(now).setUpdateTime(now);
|
.setUserRole("user").setCreateTime(now).setUpdateTime(now);
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 需要修改表,使得用户名是唯一的
|
// 需要修改表,使得用户名是唯一的
|
||||||
this.save(user);
|
this.save(user);
|
||||||
@@ -52,28 +54,15 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
|||||||
return user.getId();
|
return user.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserLoginResponse userLogin(UserLoginRequest requestParam) {
|
public UserAuthRespDTO findAuthInfoByUserAccount(String userAccount) {
|
||||||
// 1.校验
|
User one = this.lambdaQuery().eq(User::getUserAccount, userAccount).one();
|
||||||
userLoginRequestParamVerifyContext.handler(ChainMarkEnums.USER_LOGIN_REQ_PARAM_VERIFY.getMarkName(),
|
UserAuthRespDTO userAuthDTO = new UserAuthRespDTO();
|
||||||
requestParam);
|
if(one!=null){
|
||||||
User user = this.baseMapper.selectOne(Wrappers.lambdaQuery(User.class)
|
BeanUtils.copyProperties(one, userAuthDTO);
|
||||||
.eq(User::getUserAccount, requestParam.getUserAccount()));
|
return userAuthDTO;
|
||||||
if (ObjectUtil.isNull(user)
|
|
||||||
|| !passwordEncoder.matches(requestParam.getUserPassword(), user.getUserPassword())) {
|
|
||||||
throw new ServiceException("用户不存在或者密码错误", ErrorCode.NOT_LOGIN_ERROR);
|
|
||||||
}
|
}
|
||||||
// 生成 JWT
|
return null;
|
||||||
String token = jwtUtil.generateToken(user);
|
|
||||||
UserLoginResponse resp = new UserLoginResponse();
|
|
||||||
resp.setId(user.getId());
|
|
||||||
resp.setUserAccount(user.getUserAccount());
|
|
||||||
resp.setUserAvatar(user.getUserAvatar());
|
|
||||||
resp.setUserProfile(user.getUserProfile());
|
|
||||||
resp.setUserRole(user.getUserRole());
|
|
||||||
resp.setCreateTime(user.getCreateTime());
|
|
||||||
resp.setUpdateTime(user.getUpdateTime());
|
|
||||||
resp.setToken(token);
|
|
||||||
return resp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ spring:
|
|||||||
active: @env@
|
active: @env@
|
||||||
server:
|
server:
|
||||||
port: 10010
|
port: 10010
|
||||||
|
servlet:
|
||||||
|
context-path: /api
|
||||||
springdoc:
|
springdoc:
|
||||||
api-docs:
|
api-docs:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -27,6 +29,3 @@ mybatis-plus:
|
|||||||
configuration:
|
configuration:
|
||||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||||
mapper-locations: classpath*:/mapper/**/*.xml
|
mapper-locations: classpath*:/mapper/**/*.xml
|
||||||
jwt:
|
|
||||||
secret: "12345678901234567890123456789012" # 至少32字节!!
|
|
||||||
expire: 86400000 # 24小时(单位:毫秒)
|
|
||||||
2
pom.xml
2
pom.xml
@@ -20,10 +20,10 @@
|
|||||||
<module>aioj-backend-gateway</module>
|
<module>aioj-backend-gateway</module>
|
||||||
<module>aioj-backend-judge-service</module>
|
<module>aioj-backend-judge-service</module>
|
||||||
<module>aioj-backend-user-service</module>
|
<module>aioj-backend-user-service</module>
|
||||||
<module>aioj-backend-model</module>
|
|
||||||
<module>aioj-backend-question-service</module>
|
<module>aioj-backend-question-service</module>
|
||||||
<module>aioj-backend-client</module>
|
<module>aioj-backend-client</module>
|
||||||
<module>aioj-backend-ai-service</module>
|
<module>aioj-backend-ai-service</module>
|
||||||
|
<module>aioj-backend-auth</module>
|
||||||
</modules>
|
</modules>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
|||||||
Reference in New Issue
Block a user