移除鉴权

This commit is contained in:
Van0313
2025-07-13 19:13:19 +08:00
parent fda52b2aeb
commit 6e385259c0
20 changed files with 0 additions and 853 deletions

31
pom.xml
View File

@@ -90,11 +90,6 @@
<artifactId>jdk</artifactId> <artifactId>jdk</artifactId>
<version>3.0</version> <version>3.0</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId> <artifactId>jackson-mapper-asl</artifactId>
@@ -106,29 +101,7 @@
<artifactId>jackson-core-asl</artifactId> <artifactId>jackson-core-asl</artifactId>
<version>1.9.2</version> <version>1.9.2</version>
</dependency> </dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<!-- Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- AOP --> <!-- AOP -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@@ -140,10 +113,6 @@
<artifactId>httpclient</artifactId> <artifactId>httpclient</artifactId>
<version>4.5.13</version> <version>4.5.13</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -1,27 +0,0 @@
package cn.van.business.config;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration
public class KaptchaConfig {
@Bean
public DefaultKaptcha kaptchaProducer() {
DefaultKaptcha kaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 设置验证码参数
properties.setProperty("kaptcha.image.width", "150");
properties.setProperty("kaptcha.image.height", "50");
properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
properties.setProperty("kaptcha.textproducer.char.length", "4");
kaptcha.setConfig(new Config(properties));
return kaptcha;
}
}

View File

@@ -1,75 +0,0 @@
package cn.van.business.config;
import cn.van.business.filter.JwtAuthFilter;
import cn.van.business.service.impl.UserDetailsServiceImpl;
import cn.van.business.util.JwtUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.session.HttpSessionEventPublisher;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final UserDetailsServiceImpl userDetailsService;
private final JwtAuthFilter jwtAuthFilter;
public SecurityConfig(UserDetailsServiceImpl userDetailsService, JwtAuthFilter jwtAuthFilter) {
this.userDetailsService = userDetailsService;
this.jwtAuthFilter = jwtAuthFilter;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http,
PasswordEncoder passwordEncoder) throws Exception {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder);
http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.authenticationProvider(provider)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/login", "/auth/captcha","/wx/message").permitAll()
.anyRequest().authenticated());
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
}

View File

@@ -1,67 +0,0 @@
package cn.van.business.controller;
import cn.van.business.model.user.UserInfo;
import cn.van.business.util.JwtUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import java.util.Collections;
import java.util.List;
public class BaseController extends AbstractController {
@Autowired
private JwtUtils jwtUtils;
// 获取当前用户信息
protected UserInfo getCurrentUser(HttpServletRequest request) {
String token = extractToken(request);
if (token != null && jwtUtils.validateToken(token)) {
String username = jwtUtils.extractUsername(token);
// 从数据库获取用户信息
return loadUserInfo(username);
}
return null;
}
// 检查用户是否已登录
protected boolean isLogin(HttpServletRequest request) {
return getCurrentUser(request) != null;
}
// 获取当前用户ID
protected String getCurrentUserId(HttpServletRequest request) {
UserInfo user = getCurrentUser(request);
return user != null ? user.getId() : null;
}
// 获取当前用户角色
protected List<String> getCurrentUserRoles(HttpServletRequest request) {
UserInfo user = getCurrentUser(request);
return user != null ? user.getRoles() : Collections.emptyList();
}
// 提取token
private String extractToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
// 加载用户信息
private UserInfo loadUserInfo(String username) {
// 实现用户信息加载
return new UserInfo();
}
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
return null;
}
}

View File

@@ -1,46 +0,0 @@
package cn.van.business.controller.jd;
import cn.van.business.filter.RequireAuth;
import cn.van.business.model.ApiResponse;
import cn.van.business.model.jd.ProductOrder;
import cn.van.business.mq.MessageProducerService;
import cn.van.business.repository.ProductOrderRepository;
import cn.van.business.util.JDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author Leo
* @version 1.0
* @create 2024/11/7 13:39
* @description
*/
@RestController
@RequestMapping("/recordOrder")
@RequireAuth
public class OrderController {
public static String TOKEN = "dd7f298cc465e7a9791796ae1303a1f6c031a18d4894ecd9e75d44fdb0ef32d80a49e4c5811b98d8ac65d73d22a54083630d5329c7c9de2276317669ecb2e544";
@Autowired
private MessageProducerService messageProducerService;
@Autowired
private ProductOrderRepository productOrderRepository;
@RequestMapping("/list")
@ResponseBody
public ApiResponse list() throws Exception {
try {
List<ProductOrder> all = productOrderRepository.findAll();
return ApiResponse.success(all);
} catch (Exception e) {
return ApiResponse.error(500, "Server Error: " + e.getMessage());
}
}
}

View File

@@ -1,30 +0,0 @@
package cn.van.business.controller.jd.erp;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.van.business.erp.request.AuthorizeListQueryRequest;
import cn.van.business.erp.request.ERPAccount;
import cn.van.business.erp.request.ProductListQueryRequest;
import com.alibaba.fastjson2.JSONObject;
/**
* @author Leo
* @version 1.0
* @create 2025/6/17 21:06
* @description
*/
public class TestController {
public static void main(String[] args) {
//AuthorizeListQueryRequest authorizeListQueryRequest = new AuthorizeListQueryRequest(ERPAccount.ACCOUNT_HUGE, new JSONObject());
//String responseBody = authorizeListQueryRequest.getResponseBody();
//System.out.println(responseBody);
System.out.println("--------------");
ProductListQueryRequest productListQueryRequest = new ProductListQueryRequest(ERPAccount.ACCOUNT_HUGE);
JSONObject jsonObject = new JSONObject();
jsonObject.put("page_no", 1);
jsonObject.put("page_size", 1);
productListQueryRequest.setRequestBody(jsonObject);
String responseBody1 = productListQueryRequest.getResponseBody();
System.out.println(responseBody1);
}
}

View File

@@ -1,146 +0,0 @@
package cn.van.business.controller.login;
import cn.van.business.model.ApiResponse;
import cn.van.business.model.user.LoginRequest;
import cn.van.business.model.user.LoginResponse;
import cn.van.business.service.CaptchaService;
import cn.van.business.util.JwtUtils;
import cn.van.business.util.WXUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/auth")
public class AuthController {
private static final Logger logger = LoggerFactory.getLogger(AuthController.class);
private final CaptchaService captchaService;
private final JwtUtils jwtUtils;
private final AuthenticationManager authenticationManager;
private final StringRedisTemplate redisTemplate;
public AuthController(CaptchaService captchaService, JwtUtils jwtUtils, AuthenticationManager authenticationManager, StringRedisTemplate redisTemplate) {
this.captchaService = captchaService;
this.jwtUtils = jwtUtils;
this.authenticationManager = authenticationManager;
this.redisTemplate = redisTemplate;
}
private static final String USER_TOKEN_PREFIX = "user:token:";
@PostMapping("/login")
public ApiResponse login(@RequestBody LoginRequest request) {
logger.info("用户登录");
logger.info("用户名:{}", request.getUsername());
logger.info("密码:{}", request.getPassword());
logger.info("验证码:{}", request.getCaptcha());
logger.info("生成的验证码:{}", request.getGeneratedCaptcha());
// 1. 基础校验
if (StringUtils.isBlank(request.getUsername()) || StringUtils.isBlank(request.getPassword())) {
logger.error("用户名或密码不能为空");
return ApiResponse.badRequest();
}
// 2. 验证码校验
if (!captchaService.validateCaptcha(request.getCaptcha(), request.getGeneratedCaptcha())) {
logger.error("验证码错误");
return ApiResponse.badRequest();
}
// 在验证码校验后、认证前添加防爆破逻辑
String loginFailKey = "login:fail:" + request.getUsername();
Long failCount = redisTemplate.opsForValue().increment(loginFailKey);
if (failCount != null && failCount > 5) {
logger.error("尝试次数过多,请稍后再试");
return ApiResponse.badRequest();
}else {
redisTemplate.expire(loginFailKey, 5, TimeUnit.MINUTES);
}
// 3. 用户认证Spring Security 标准流程)
logger.info("3. 用户认证Spring Security 标准流程)");
try {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
} catch (Exception e) {
logger.error("用户认证失败:{}", e.getMessage());
}
// 4. 生成 JWT Token
logger.info("用户认证成功");
String token = jwtUtils.generateToken(request.getUsername());
String refreshToken = generateRefreshToken(request.getUsername());
logger.info("生成 JWT Token{}", token);
// 5. 存入 Redis
saveUserToken(request.getUsername(), token, jwtUtils.getExpiration(token));
// 6. 构造响应
LoginResponse response = new LoginResponse();
response.setToken(token);
response.setRefreshToken(refreshToken);
response.setUsername(request.getUsername());
return ApiResponse.success(response);
}
@PostMapping("/logout")
public ApiResponse logout(@RequestHeader("Authorization") String token) {
String actualToken = token.startsWith("Bearer ") ? token.substring(7) : token;
String username = jwtUtils.extractUsername(actualToken);
String userKey = USER_TOKEN_PREFIX + username;
// 从 Redis 删除用户 Token
redisTemplate.delete(userKey);
// 添加 Token 到黑名单
addToBlacklist(actualToken, jwtUtils.getRemainingExpirationTime(actualToken));
return ApiResponse.success();
}
@GetMapping("/captcha")
public ApiResponse<String> getCaptcha() throws Exception {
logger.info("获取验证码");
String captchaImage = captchaService.generateCaptchaImage();
return ApiResponse.success(captchaImage);
}
/**
* 将用户 Token 存入 Redis并设置相同有效期
*/
private void saveUserToken(String username, String token, long expiration) {
String key = USER_TOKEN_PREFIX + username;
redisTemplate.opsForValue().set(key, token, expiration, TimeUnit.MILLISECONDS);
}
/**
* 将 Token 加入黑名单
*/
private void addToBlacklist(String token, long remainingTime) {
String blacklistKey = "blacklist:token:" + token;
redisTemplate.opsForValue().set(blacklistKey, "invalid", remainingTime, TimeUnit.MILLISECONDS);
}
/**
* 生成刷新 TokenRefresh Token
*/
private String generateRefreshToken(String username) {
return jwtUtils.generateToken(username);
}
}

View File

@@ -1,24 +0,0 @@
package cn.van.business.controller.login;
import cn.van.business.service.CaptchaService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/captcha")
public class CaptchaController {
private final CaptchaService captchaService;
public CaptchaController(CaptchaService captchaService) {
this.captchaService = captchaService;
}
@GetMapping("/generate")
public ResponseEntity<String> generateCaptcha() throws Exception {
String base64Image = captchaService.generateCaptchaImage();
return ResponseEntity.ok(base64Image);
}
}

View File

@@ -1,63 +0,0 @@
package cn.van.business.filter;
import cn.van.business.service.impl.UserDetailsServiceImpl;
import cn.van.business.util.JwtUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
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;
@Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
private final JwtUtils jwtUtils;
private final UserDetailsServiceImpl userDetailsService;
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain)
throws ServletException, IOException {
try {
logger.debug("JwtAuthFilter.doFilterInternal");
String jwt = parseJwt(request);
if (jwt != null && jwtUtils.validateToken(jwt)) {
String username = jwtUtils.extractUsername(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
logger.error("无法认证用户: {}");
}
filterChain.doFilter(request, response);
}
private String parseJwt(HttpServletRequest request) {
String headerAuth = request.getHeader("Authorization");
if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
return headerAuth.substring(7);
}
return null;
}
}

View File

@@ -1,13 +0,0 @@
package cn.van.business.filter;
import org.springframework.security.access.prepost.PreAuthorize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
public @interface RequireAuth {}

View File

@@ -1,18 +0,0 @@
CREATE TABLE product_order
(
id BIGINT AUTO_INCREMENT NOT NULL,
sku_name VARCHAR(255) NULL,
sku_type INT NULL,
order_id VARCHAR(255) NULL,
order_time datetime NULL,
order_account VARCHAR(255) NULL,
is_reviewed BIT(1) NULL,
review_time datetime NULL,
is_cashback_received BIT(1) NULL,
cashback_time datetime NULL,
recipient_name VARCHAR(255) NULL,
recipient_phone VARCHAR(255) NULL,
recipient_address VARCHAR(255) NULL,
who_order VARCHAR(255) NULL,
CONSTRAINT pk_product_order PRIMARY KEY (id)
);

View File

@@ -1,46 +0,0 @@
package cn.van.business.model.user;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import lombok.Getter;
import lombok.Setter;
import jakarta.persistence.*;
import java.time.LocalDateTime;
/**
* @author Leo
* @version 1.0
* @create 2025/6/16 10:55
* @description
*/
@Getter
@Setter
@Entity
@Table(name = "admin_users")
public class AdminUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
private String password;
private String nickname;
private String avatarUrl;
private String roles; // 角色列表,可用逗号分隔
private LocalDateTime lastLoginTime;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}

View File

@@ -1,13 +0,0 @@
package cn.van.business.model.user;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class LoginRequest {
private String username;
private String password;
private String captcha; // 验证码字段(如果需要)
private String generatedCaptcha;
}

View File

@@ -1,14 +0,0 @@
package cn.van.business.model.user;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class LoginResponse {
private String token;
private Long expiresIn;
private String refreshToken;
private UserInfo userInfo;
private String username;
}

View File

@@ -1,16 +0,0 @@
package cn.van.business.model.user;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class UserInfo {
private String username;
private String nickname;
private String id;
private List<String> roles;
private String avatarUrl;
}

View File

@@ -1,32 +0,0 @@
package cn.van.business.service;
import cn.hutool.crypto.digest.MD5;
import cn.van.business.model.user.AdminUser;
import cn.van.business.util.Util;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@Service
public class AdminUserService {
// 模拟数据库存储
private static final Map<String, AdminUser> users = new HashMap<>();
static {
// 初始化一个测试用户(生产环境应从数据库加载)
AdminUser user = new AdminUser();
user.setUsername("van");
String password = Util.md5("LK.807878712");
user.setPassword(new BCryptPasswordEncoder().encode(password));
users.put("van", user);
}
public AdminUser findByUsername(String username) {
return users.get(username);
}
}

View File

@@ -1,32 +0,0 @@
package cn.van.business.service;
import com.google.code.kaptcha.Producer;
import org.springframework.stereotype.Service;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
@Service
public class CaptchaService {
private final Producer kaptchaProducer;
public CaptchaService(Producer kaptchaProducer) {
this.kaptchaProducer = kaptchaProducer;
}
public String generateCaptchaImage() throws Exception {
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(image, "PNG", outputStream);
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
}
public boolean validateCaptcha(String userInput, String generatedCaptcha) {
return userInput.equalsIgnoreCase("Succ");
}
}

View File

@@ -1,36 +0,0 @@
package cn.van.business.service.impl;
import cn.van.business.model.user.AdminUser;
import cn.van.business.service.AdminUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.ArrayList;
import java.util.Collection;
import java.util.Collections;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private AdminUserService adminUserService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
AdminUser user = adminUserService.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
return User.builder()
.username(user.getUsername())
.password(user.getPassword())
.build();
}
}

View File

@@ -1,18 +0,0 @@
package cn.van.business.util;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class AuthEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "需要登录认证");
}
}

View File

@@ -1,106 +0,0 @@
package cn.van.business.util;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* JWT 工具类
* 提供 token 的生成、解析、验证和有效期管理功能
*/
@Component
public class JwtUtils {
private final String secret = "7b4c86d11fe2b64a5ce4d7d83de881b4afa76bf4a8bbc13ee50676c20b14c0835dda8a78a5a795b0f2201a26f758301b56ffbc52d021e158f1365d8be22fa6d7"; // 应配置在 application.yml 中
private final long expiration = 86400000 * 7; // 24小时
/**
* 生成一个新的 JWT Token
* @param username 用户名
* @param roles 用户角色(可选)
* @return 返回生成的 JWT Token 字符串
*/
// 生成 Token 时去掉 roles 参数
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
/**
* 从给定的 JWT Token 中提取用户名
*
* @param token JWT Token
* @return 提取的用户名
*/
public String extractUsername(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
/**
* 获取 JWT Token 的过期时间
*
* @param token JWT Token
* @return 返回 token 的过期时间 (Date)
*/
public Date extractExpiration(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getExpiration();
}
/**
* 验证指定的 JWT Token 是否有效
*
* @param token JWT Token
* @return 如果 token 有效则返回 true否则返回 false
*/
public Boolean validateToken(String token) {
return !isTokenExpired(token);
}
/**
* 检查 token 是否已过期
*
* @param token JWT Token
* @return 如果已过期返回 true否则返回 false
*/
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
/**
* 获取 JWT Token 的剩余有效时间(毫秒)
*
* @param token JWT Token
* @return 剩余的有效时间(毫秒)
*/
public long getRemainingExpirationTime(String token) {
long now = System.currentTimeMillis();
return Math.max(0, extractExpiration(token).getTime() - now);
}
/**
* 获取 JWT Token 的过期时间(毫秒)
*
* @param token JWT Token
* @return 返回 token 的过期时间戳(毫秒)
*/
public long getExpiration(String token) {
return extractExpiration(token).getTime();
}
}