diff --git a/src/main/java/com/onekeycall/videotablet/config/SecurityConfig.java b/src/main/java/com/onekeycall/videotablet/config/SecurityConfig.java index b535a90..db14cbb 100644 --- a/src/main/java/com/onekeycall/videotablet/config/SecurityConfig.java +++ b/src/main/java/com/onekeycall/videotablet/config/SecurityConfig.java @@ -25,10 +25,11 @@ public class SecurityConfig { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth - .requestMatchers("/public/**").permitAll() - .requestMatchers("/admin/**").hasRole("ADMIN") - .requestMatchers("/user/**").hasAnyRole("USER", "ADMIN") - .anyRequest().authenticated() + .requestMatchers("/public/**").permitAll() + .requestMatchers("/admin/**").hasRole("ADMIN") +// .requestMatchers("/user/**").hasAnyRole("USER", "ADMIN") + .requestMatchers("/user/**").permitAll() + .anyRequest().authenticated() ); return http.build(); } diff --git a/src/main/java/com/onekeycall/videotablet/config/WebConfig.java b/src/main/java/com/onekeycall/videotablet/config/WebConfig.java new file mode 100644 index 0000000..f4ccbfd --- /dev/null +++ b/src/main/java/com/onekeycall/videotablet/config/WebConfig.java @@ -0,0 +1,20 @@ +package com.onekeycall.videotablet.config; + +import com.onekeycall.videotablet.interceptor.TokenInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +//@Configuration +//public class WebConfig implements WebMvcConfigurer { +// @Autowired +// private TokenInterceptor tokenInterceptor; +// +// @Override +// public void addInterceptors(InterceptorRegistry registry) { +// registry.addInterceptor(tokenInterceptor) +// .addPathPatterns("/user/**") // 保护用户相关端点 +// .excludePathPatterns("/public/**"); // 开放登录注册 +// } +//} diff --git a/src/main/java/com/onekeycall/videotablet/controller/LoginController.java b/src/main/java/com/onekeycall/videotablet/controller/LoginController.java index 8b26b7e..47f192d 100644 --- a/src/main/java/com/onekeycall/videotablet/controller/LoginController.java +++ b/src/main/java/com/onekeycall/videotablet/controller/LoginController.java @@ -48,8 +48,8 @@ public class LoginController { @PostMapping("/login") public ResponseEntity login( - @RequestParam(value = "user_id") String userId, @RequestParam String password, - @RequestParam(value = "device_id", required = false) String deviceId) { + @RequestHeader("Device-ID") String deviceId, + @RequestParam(value = "user_id") String userId, @RequestParam String password) { // 1. 创建认证令牌 Authentication authenticationToken = new UsernamePasswordAuthenticationToken(userId, password); @@ -57,8 +57,8 @@ public class LoginController { Authentication authentication = authenticationManager.authenticate(authenticationToken); // 3. 认证成功后生成 JWT - UserDetails userDetails = (UserDetails) authentication.getPrincipal(); - TokenPair tokenPair = jwtUtil.generateTokenPair(userDetails.getUsername(), deviceId); + User userDetails = (User) authentication.getPrincipal(); + TokenPair tokenPair = jwtUtil.generateTokenPair(userDetails.getUserId(), deviceId); // 4. 返回 Token return ResponseEntity.ok(Collections.singletonMap("token", tokenPair.toMap())); diff --git a/src/main/java/com/onekeycall/videotablet/controller/UserPasswordController.java b/src/main/java/com/onekeycall/videotablet/controller/UserPasswordController.java index 7d788dc..e5c834f 100644 --- a/src/main/java/com/onekeycall/videotablet/controller/UserPasswordController.java +++ b/src/main/java/com/onekeycall/videotablet/controller/UserPasswordController.java @@ -8,10 +8,7 @@ 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; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/user") @@ -30,54 +27,49 @@ public class UserPasswordController { this.authenticationManager = authenticationManager; } - @PostMapping("/phone_set_password") + @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 { + @RequestHeader("Authorization") String authHeader, @RequestHeader("Device-ID") String deviceId, + @RequestParam(value = "user_id") String userId, + @RequestParam String password, @RequestParam(value = "verify_password") String verifyPassword) { + + if (authHeader == null || !authHeader.startsWith("Bearer ")) { return Result.error().message("Authorization header is incorrect"); } + + if (!StringUtils.equals(password, verifyPassword)) { + return Result.error().message("password is not same"); + } + String token = authHeader.substring(7); // 提取真正的Token + 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"); + } } @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 { + @RequestHeader("Authorization") String authHeader, @RequestHeader("Device-ID") String deviceId, + @RequestParam(value = "user_id") String userId, @RequestParam(value = "old_password") String oldPassword, + @RequestParam String password, @RequestParam(value = "verify_password") String verifyPassword) { + if (authHeader == null || !authHeader.startsWith("Bearer ")) { return Result.error().message("Authorization header is incorrect"); } + + String token = authHeader.substring(7); + if (!StringUtils.equals(password, verifyPassword)) { + return Result.error().message("password is not same"); + } + if (oldPassword.equals(password)) { + return Result.error().message("The old password and the new password are the same"); + + } + if (jwtUtil.validateAccessToken(userId, token, deviceId)) { + return userService.changePassword(userId, oldPassword, password); + } else { + return Result.error().message("token is not same"); + } } } diff --git a/src/main/java/com/onekeycall/videotablet/entity/DeviceInfo.java b/src/main/java/com/onekeycall/videotablet/entity/DeviceInfo.java new file mode 100644 index 0000000..9c4e412 --- /dev/null +++ b/src/main/java/com/onekeycall/videotablet/entity/DeviceInfo.java @@ -0,0 +1,34 @@ +package com.onekeycall.videotablet.entity; + +import jakarta.persistence.*; +import lombok.Getter; + +import java.util.Date; + +@Getter +@Entity +@Table(name = "devices_sn") +public class DeviceInfo { + @Id + @Column(name = "sn", unique = true, nullable = false) + private String sn; + + @Column(name = "device_model", nullable = false) + private String device_model; + + @Column(name = "device_alias") + private String deviceAlias; + + @Column(name = "user_id") + private String userId; + + @Column(name = "bind_phone") + private String bind_phone; + + @Column(name = "add_time", nullable = false) + private Date add_time; + + @Column(name = "activation_time") + private Date activation_time; + +} diff --git a/src/main/java/com/onekeycall/videotablet/entity/User.java b/src/main/java/com/onekeycall/videotablet/entity/User.java index b70702c..81e5b5b 100644 --- a/src/main/java/com/onekeycall/videotablet/entity/User.java +++ b/src/main/java/com/onekeycall/videotablet/entity/User.java @@ -25,7 +25,7 @@ public class User implements UserDetails { @Column(name = "user_id", unique = true, nullable = false) private String userId; - @Column(unique = true) + @Column private String nickname; @Column() @@ -34,16 +34,16 @@ public class User implements UserDetails { @Column(unique = true, nullable = false) private String phone; - @Column(name = "create_time", unique = true, nullable = false) + @Column(name = "create_time",unique = true, nullable = false) private Date creatTime; - @Column(name = "last_login_time", unique = true, nullable = false) + @Column(name = "last_login_time") private Date lastLoginTime; - @Column(name = "update_time", unique = true, nullable = false) + @Column(name = "update_time") private Date updateTime; - @Column(name = "device_id", unique = true, nullable = false) + @Column(name = "device_id", nullable = false) private String deviceId; @Override diff --git a/src/main/java/com/onekeycall/videotablet/interceptor/TokenInterceptor.java b/src/main/java/com/onekeycall/videotablet/interceptor/TokenInterceptor.java new file mode 100644 index 0000000..6edd2a5 --- /dev/null +++ b/src/main/java/com/onekeycall/videotablet/interceptor/TokenInterceptor.java @@ -0,0 +1,63 @@ +package com.onekeycall.videotablet.interceptor; + +import com.onekeycall.videotablet.utils.JwtUtil; +import io.jsonwebtoken.Claims; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +@Component +public class TokenInterceptor implements HandlerInterceptor { + + @Autowired + private JwtUtil jwtUtil; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + // 1. 获取并校验Authorization头 + String authHeader = request.getHeader("Authorization"); + if (authHeader == null || !authHeader.startsWith("Bearer ")) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Missing or invalid Authorization header"); + return false; + } + String token = authHeader.substring(7); + + // 2. 获取设备ID(强制要求客户端传递) + String deviceId = request.getHeader("Device-ID"); + if (deviceId == null || deviceId.isEmpty()) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Device-ID header is required"); + return false; + } + + try { + // 3. 解析Token基础信息 + Claims claims = jwtUtil.parseToken(token); + + // 4. 验证Token类型必须为ACCESS + String tokenType = claims.get("type", String.class); + if (!"ACCESS".equals(tokenType)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid token type"); + return false; + } + + // 5. 验证设备ID绑定 + String tokenDeviceId = claims.get("deviceId", String.class); + if (!deviceId.equals(tokenDeviceId)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Device binding mismatch"); + return false; + } + + // 6. 传递用户信息到后续流程 + request.setAttribute("userId", claims.getSubject()); + request.setAttribute("deviceId", deviceId); + return true; + + } catch (Exception e) { + // 7. 统一异常处理 + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token validation failed: " + e.getMessage()); + return false; + } + } +} \ No newline at end of file