主备迁移只webflux
This commit is contained in:
19
pom.xml
19
pom.xml
@@ -35,16 +35,26 @@
|
|||||||
</scm>
|
</scm>
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>21</java.version>
|
<java.version>21</java.version>
|
||||||
|
<spring-cloud.version>2025.0.0</spring-cloud.version>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<!-- <dependency>-->
|
||||||
<groupId>org.springframework.boot</groupId>
|
<!-- <groupId>org.springframework.cloud</groupId>-->
|
||||||
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
|
<!-- <artifactId>spring-cloud-starter-gateway</artifactId>-->
|
||||||
</dependency>
|
<!-- <version>4.3.0</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||||
|
<!-- <artifactId>spring-boot-starter-webflux</artifactId>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||||
@@ -148,7 +158,6 @@
|
|||||||
<version>3.1.499</version> <!-- 推荐稳定版本 -->
|
<version>3.1.499</version> <!-- 推荐稳定版本 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public class SecurityConfig {
|
|||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
.requestMatchers("/public/**").permitAll()
|
.requestMatchers("/public/**").permitAll()
|
||||||
.requestMatchers("/admin/**").hasRole("ADMIN")
|
.requestMatchers("/admin/**").hasRole("ADMIN")
|
||||||
|
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
);
|
);
|
||||||
return http.build();
|
return http.build();
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import com.onekeycall.videotablet.entity.User;
|
|||||||
import com.onekeycall.videotablet.result.Result;
|
import com.onekeycall.videotablet.result.Result;
|
||||||
import com.onekeycall.videotablet.service.UserService;
|
import com.onekeycall.videotablet.service.UserService;
|
||||||
import com.onekeycall.videotablet.utils.JwtUtil;
|
import com.onekeycall.videotablet.utils.JwtUtil;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
@@ -15,14 +14,12 @@ import org.springframework.security.authentication.AuthenticationManager;
|
|||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
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.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
@RequestMapping("/public")
|
||||||
public class LoginController {
|
public class LoginController {
|
||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
@@ -39,7 +36,7 @@ public class LoginController {
|
|||||||
this.authenticationManager = authenticationManager;
|
this.authenticationManager = authenticationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/public/register")
|
@PostMapping("/register")
|
||||||
public ResponseEntity<?> registerUser(@RequestBody RegisterRequest registerRequest) {
|
public ResponseEntity<?> registerUser(@RequestBody RegisterRequest registerRequest) {
|
||||||
try {
|
try {
|
||||||
userService.registerUser(registerRequest.getUsername(), registerRequest.getPassword());
|
userService.registerUser(registerRequest.getUsername(), registerRequest.getPassword());
|
||||||
@@ -49,7 +46,7 @@ public class LoginController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/public/login")
|
@PostMapping("/login")
|
||||||
public ResponseEntity<?> login(
|
public ResponseEntity<?> login(
|
||||||
@RequestParam(value = "user_id") String userId, @RequestParam String password,
|
@RequestParam(value = "user_id") String userId, @RequestParam String password,
|
||||||
@RequestParam(value = "device_id", required = false) String deviceId) {
|
@RequestParam(value = "device_id", required = false) String deviceId) {
|
||||||
@@ -91,7 +88,7 @@ public class LoginController {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/public/registerByPhone")
|
@PostMapping("/phone_register")
|
||||||
public Result registerByPhone(
|
public Result registerByPhone(
|
||||||
@RequestParam String phone, @RequestParam String code,
|
@RequestParam String phone, @RequestParam String code,
|
||||||
@RequestParam(value = "verify_key") String verifyKey, @RequestParam(value = "device_id") String deviceId) {
|
@RequestParam(value = "verify_key") String verifyKey, @RequestParam(value = "device_id") String deviceId) {
|
||||||
@@ -129,7 +126,7 @@ public class LoginController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/public/loginByPhone")
|
@PostMapping("/phone_login")
|
||||||
public Result loginByPhone(
|
public Result loginByPhone(
|
||||||
@RequestParam String phone, @RequestParam String code,
|
@RequestParam String phone, @RequestParam String code,
|
||||||
@RequestParam(value = "verify_key") String verifyKey, @RequestParam(value = "device_id") String deviceId) {
|
@RequestParam(value = "verify_key") String verifyKey, @RequestParam(value = "device_id") String deviceId) {
|
||||||
@@ -161,54 +158,5 @@ public class LoginController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/public/setPasswordByPhone")
|
|
||||||
public Result setPasswordByPhone(
|
|
||||||
HttpServletRequest request, @RequestParam(value = "user_id") String userId,
|
|
||||||
@RequestParam String password, @RequestParam(value = "verify_password") String verifyPassword,
|
|
||||||
@RequestParam(value = "device_id") String deviceId) {
|
|
||||||
String authHeader = request.getHeader("Authorization");
|
|
||||||
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
|
||||||
String token = authHeader.substring(7); // 提取真正的Token
|
|
||||||
if (StringUtils.equals(password, verifyPassword)) {
|
|
||||||
if (jwtUtil.validateAccessToken(userId, token, deviceId)) {
|
|
||||||
userService.setPasswordByUserId(userId, password);
|
|
||||||
return Result.ok().message("set password success");
|
|
||||||
} else {
|
|
||||||
return Result.error().message("token is not same");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Result.error().message("password is not same");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Result.error().message("Authorization header is incorrect");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/public/changePassword")
|
|
||||||
public Result changePassword(
|
|
||||||
HttpServletRequest request,
|
|
||||||
@RequestParam(value = "user_id") String userId,
|
|
||||||
@RequestParam(value = "old_password") String oldPassword,
|
|
||||||
@RequestParam String password, @RequestParam(value = "verify_password") String verifyPassword,
|
|
||||||
@RequestParam(value = "device_id") String deviceId) {
|
|
||||||
String authHeader = request.getHeader("Authorization");
|
|
||||||
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
|
||||||
String token = authHeader.substring(7);
|
|
||||||
if (StringUtils.equals(password, verifyPassword)) {
|
|
||||||
if (!oldPassword.equals(password)) {
|
|
||||||
if (jwtUtil.validateAccessToken(userId, token, deviceId)) {
|
|
||||||
return userService.changePassword(userId, oldPassword, password);
|
|
||||||
} else {
|
|
||||||
return Result.error().message("token is not same");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Result.error().message("The old password and the new password are the same");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Result.error().message("password is not same");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Result.error().message("Authorization header is incorrect");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.onekeycall.videotablet.controller;
|
||||||
|
|
||||||
|
import com.onekeycall.videotablet.result.Result;
|
||||||
|
import com.onekeycall.videotablet.service.UserService;
|
||||||
|
import com.onekeycall.videotablet.utils.JwtUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/user")
|
||||||
|
public class UserPasswordController {
|
||||||
|
private final UserService userService;
|
||||||
|
private final AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
@Autowired
|
||||||
|
private JwtUtil jwtUtil;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UserPasswordController(UserService userService, AuthenticationManager authenticationManager) {
|
||||||
|
this.userService = userService;
|
||||||
|
this.authenticationManager = authenticationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/phone_set_password")
|
||||||
|
public Result setPasswordByPhone(
|
||||||
|
HttpServletRequest request, @RequestParam(value = "user_id") String userId,
|
||||||
|
@RequestParam String password, @RequestParam(value = "verify_password") String verifyPassword,
|
||||||
|
@RequestParam(value = "device_id") String deviceId) {
|
||||||
|
String authHeader = request.getHeader("Authorization");
|
||||||
|
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
||||||
|
String token = authHeader.substring(7); // 提取真正的Token
|
||||||
|
if (StringUtils.equals(password, verifyPassword)) {
|
||||||
|
if (jwtUtil.validateAccessToken(userId, token, deviceId)) {
|
||||||
|
userService.setPasswordByUserId(userId, password);
|
||||||
|
return Result.ok().message("set password success");
|
||||||
|
} else {
|
||||||
|
return Result.error().message("token is not same");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Result.error().message("password is not same");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Result.error().message("Authorization header is incorrect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/change_password")
|
||||||
|
public Result changePassword(
|
||||||
|
HttpServletRequest request,
|
||||||
|
@RequestParam(value = "user_id") String userId,
|
||||||
|
@RequestParam(value = "old_password") String oldPassword,
|
||||||
|
@RequestParam String password, @RequestParam(value = "verify_password") String verifyPassword,
|
||||||
|
@RequestParam(value = "device_id") String deviceId) {
|
||||||
|
String authHeader = request.getHeader("Authorization");
|
||||||
|
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
||||||
|
String token = authHeader.substring(7);
|
||||||
|
if (StringUtils.equals(password, verifyPassword)) {
|
||||||
|
if (!oldPassword.equals(password)) {
|
||||||
|
if (jwtUtil.validateAccessToken(userId, token, deviceId)) {
|
||||||
|
return userService.changePassword(userId, oldPassword, password);
|
||||||
|
} else {
|
||||||
|
return Result.error().message("token is not same");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Result.error().message("The old password and the new password are the same");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Result.error().message("password is not same");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Result.error().message("Authorization header is incorrect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,12 +9,12 @@ import java.util.Collections;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "users")
|
@Table(name = "ordinary_users")
|
||||||
public class User implements UserDetails {
|
public class User implements UserDetails {
|
||||||
|
|
||||||
@Transient // 关键注解:声明此字段不映射到数据库
|
@Transient // 关键注解:声明此字段不映射到数据库
|
||||||
private boolean newUser;
|
private boolean newUser;
|
||||||
@Transient // 关键注解:声明此字段不映射到数据库
|
@Transient
|
||||||
private boolean hasPassword;
|
private boolean hasPassword;
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.onekeycall.videotablet.handler;
|
|||||||
|
|
||||||
import com.onekeycall.videotablet.result.Result;
|
import com.onekeycall.videotablet.result.Result;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.validation.FieldError;
|
import org.springframework.validation.FieldError;
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||||
@@ -9,7 +10,9 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
|
|||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -23,6 +26,14 @@ import java.util.Map;
|
|||||||
@ControllerAdvice
|
@ControllerAdvice
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
// 替换为 WebFlux 的异常处理
|
||||||
|
// @ExceptionHandler(ResponseStatusException.class)
|
||||||
|
// public Mono<ResponseEntity<String>> handleResponseStatusException(ResponseStatusException ex) {
|
||||||
|
// return Mono.just(ResponseEntity
|
||||||
|
// .status(ex.getStatusCode())
|
||||||
|
// .body(ex.getReason()));
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用ExceptionHandler注解声明处理Exception异常
|
* 使用ExceptionHandler注解声明处理Exception异常
|
||||||
*
|
*
|
||||||
@@ -51,12 +62,12 @@ public class GlobalExceptionHandler {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||||
@ExceptionHandler(NoResourceFoundException.class)
|
@ExceptionHandler(NoResourceFoundException.class)
|
||||||
public Result handleNoResourceFoundException(NoResourceFoundException ex) {
|
public ResponseEntity<?> handleNoResourceFoundException(NoResourceFoundException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
// 新版本 Spring(推荐)我没有这个方法
|
// 新版本 Spring(推荐)我没有这个方法
|
||||||
// return ResponseEntity.notFound().body(error);
|
// return ResponseEntity.notFound().body(error);
|
||||||
// 旧版本 Spring(兼容写法)
|
// 旧版本 Spring(兼容写法)
|
||||||
return Result.notFound().message("检查网址是否正确");
|
return new ResponseEntity<>(Result.notFound().message("检查网址是否正确"), HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
|
|||||||
@@ -29,11 +29,12 @@ public class JwtUtil {
|
|||||||
private Long refreshExpire;
|
private Long refreshExpire;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 生成双Token(关联设备指纹)
|
||||||
|
*
|
||||||
* @param userId 统一使用user_id
|
* @param userId 统一使用user_id
|
||||||
* @param deviceId
|
* @param deviceId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
// 生成双Token(关联设备指纹)
|
|
||||||
public TokenPair generateTokenPair(String userId, String deviceId) {
|
public TokenPair generateTokenPair(String userId, String deviceId) {
|
||||||
String accessToken = Jwts.builder()
|
String accessToken = Jwts.builder()
|
||||||
.subject(userId)
|
.subject(userId)
|
||||||
@@ -64,7 +65,13 @@ public class JwtUtil {
|
|||||||
return new TokenPair(accessToken, refreshToken, accessExpire, refreshExpire, deviceId);
|
return new TokenPair(accessToken, refreshToken, accessExpire, refreshExpire, deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析Token并返回Claims
|
|
||||||
|
/**
|
||||||
|
* 解析Token并返回Claims
|
||||||
|
*
|
||||||
|
* @param token
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Claims parseToken(String token) {
|
public Claims parseToken(String token) {
|
||||||
try {
|
try {
|
||||||
return Jwts.parser()
|
return Jwts.parser()
|
||||||
@@ -77,7 +84,14 @@ public class JwtUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验Access Token有效性(签名+过期时间+设备绑定)
|
/**
|
||||||
|
* 校验Access Token有效性(签名+过期时间+设备绑定)
|
||||||
|
*
|
||||||
|
* @param userId
|
||||||
|
* @param accessToken
|
||||||
|
* @param deviceId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean validateAccessToken(String userId, String accessToken, String deviceId) {
|
public boolean validateAccessToken(String userId, String accessToken, String deviceId) {
|
||||||
Claims claims = parseToken(accessToken);
|
Claims claims = parseToken(accessToken);
|
||||||
|
|
||||||
@@ -102,7 +116,14 @@ public class JwtUtil {
|
|||||||
return true; // 通过所有校验
|
return true; // 通过所有校验
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验Refresh Token有效性(签名+Redis一致性)
|
|
||||||
|
/**
|
||||||
|
* 校验Refresh Token有效性(签名+Redis一致性)
|
||||||
|
*
|
||||||
|
* @param refreshToken
|
||||||
|
* @param username
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean validateRefreshToken(String refreshToken, String username) {
|
public boolean validateRefreshToken(String refreshToken, String username) {
|
||||||
Claims claims = parseToken(refreshToken);
|
Claims claims = parseToken(refreshToken);
|
||||||
|
|
||||||
@@ -127,7 +148,14 @@ public class JwtUtil {
|
|||||||
return true; // 通过所有校验
|
return true; // 通过所有校验
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用Refresh Token刷新Access Token
|
|
||||||
|
/**
|
||||||
|
* 使用Refresh Token刷新Access Token
|
||||||
|
*
|
||||||
|
* @param refreshToken
|
||||||
|
* @param deviceId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public TokenPair refreshAccessToken(String refreshToken, String deviceId) {
|
public TokenPair refreshAccessToken(String refreshToken, String deviceId) {
|
||||||
Claims claims = parseToken(refreshToken);
|
Claims claims = parseToken(refreshToken);
|
||||||
String userId = claims.getSubject();
|
String userId = claims.getSubject();
|
||||||
|
|||||||
Reference in New Issue
Block a user