增加统一token验证,未完成
This commit is contained in:
@@ -7,8 +7,5 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
@Configuration
|
||||
public class CommonConfig {
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +1,31 @@
|
||||
package com.onekeycall.videotablet.config;
|
||||
|
||||
import com.onekeycall.videotablet.filter.JwtAuthenticationFilter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
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;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class SecurityConfig {
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
private final JwtAuthenticationFilter jwtAuthenticationFilter; // 自定义的JWT认证过滤器
|
||||
|
||||
@Autowired
|
||||
public SecurityConfig(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
public SecurityConfig(@Lazy JwtAuthenticationFilter jwtAuthenticationFilter) {
|
||||
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -38,6 +45,7 @@ public class SecurityConfig {
|
||||
.requestMatchers("/contact/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); // 添加JWT过滤器
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@@ -46,4 +54,9 @@ public class SecurityConfig {
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
|
||||
return authConfig.getAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
||||
@@ -144,6 +144,7 @@ public class UserController {
|
||||
|
||||
@GetMapping("/get_device_apk_list")
|
||||
public Result getDeviceApkList(@RequestParam String sn) {
|
||||
|
||||
DeviceApkInfo deviceApkInfo = deviceApkInfoService.getDeviceApkInfoBySn(sn);
|
||||
return Result.ok().data("deviceApkInfo", deviceApkInfo);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.onekeycall.videotablet.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
|
||||
@@ -15,6 +16,7 @@ public class DeviceApkInfo {
|
||||
@Id
|
||||
private String id; // MongoDB文档ID
|
||||
|
||||
@Indexed
|
||||
@Field("sn")
|
||||
private String sn; // 设备序列号
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.onekeycall.videotablet.filter;
|
||||
import com.onekeycall.videotablet.utils.JwtUtil;
|
||||
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.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
private final JwtUtil jwtUtil;
|
||||
|
||||
public JwtAuthenticationFilter(UserDetailsService userDetailsService, JwtUtil jwtUtil) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.jwtUtil = jwtUtil;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
// 从请求头中获取Token
|
||||
String authorizationHeader = request.getHeader("Authorization");
|
||||
|
||||
String username = null;
|
||||
String jwt = null;
|
||||
|
||||
// 检查Authorization头是否存在且以Bearer开头
|
||||
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
|
||||
jwt = authorizationHeader.substring(7);
|
||||
try {
|
||||
username = jwtUtil.getUsernameFromToken(jwt);
|
||||
} catch (Exception e) {
|
||||
logger.error("无法获取用户信息或Token无效", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果获取到用户名且当前上下文没有认证信息
|
||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
|
||||
|
||||
// 验证Token
|
||||
if (jwtUtil.validateToken(jwt, userDetails)) {
|
||||
// 创建认证令牌
|
||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
userDetails, null, userDetails.getAuthorities());
|
||||
|
||||
usernamePasswordAuthenticationToken
|
||||
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
|
||||
// 将认证信息存入上下文
|
||||
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
|
||||
}
|
||||
}
|
||||
|
||||
// 继续过滤器链
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Component
|
||||
public class JwtUtil {
|
||||
@@ -188,6 +188,60 @@ public class JwtUtil {
|
||||
redisTemplate.delete(redisKey);
|
||||
}
|
||||
|
||||
// 从Token中获取用户名
|
||||
public String getUsernameFromToken(String token) {
|
||||
return getClaimFromToken(token, Claims::getSubject);
|
||||
}
|
||||
|
||||
// 从Token中获取过期时间
|
||||
public Date getExpirationDateFromToken(String token) {
|
||||
return getClaimFromToken(token, Claims::getExpiration);
|
||||
}
|
||||
|
||||
// 从Token中获取自定义声明
|
||||
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
|
||||
final Claims claims = getAllClaimsFromToken(token);
|
||||
return claimsResolver.apply(claims);
|
||||
}
|
||||
|
||||
// 从Token中获取所有声明
|
||||
private Claims getAllClaimsFromToken(String token) {
|
||||
return Jwts.parser()
|
||||
.setSigningKey(secret)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
// 检查Token是否过期
|
||||
private Boolean isTokenExpired(String token) {
|
||||
final Date expiration = getExpirationDateFromToken(token);
|
||||
return expiration.before(new Date());
|
||||
}
|
||||
|
||||
// 生成Token
|
||||
public String generateToken(UserDetails userDetails) {
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
return doGenerateToken(claims, userDetails.getUsername());
|
||||
}
|
||||
|
||||
// 生成Token的具体实现
|
||||
private String doGenerateToken(Map<String, Object> claims, String subject) {
|
||||
return Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.setSubject(subject)
|
||||
.setIssuedAt(new Date(System.currentTimeMillis()))
|
||||
.setExpiration(new Date(System.currentTimeMillis() + accessExpire))
|
||||
.signWith(SignatureAlgorithm.HS512, secret)
|
||||
.compact();
|
||||
}
|
||||
|
||||
// 验证Token
|
||||
public Boolean validateToken(String token, UserDetails userDetails) {
|
||||
final String username = getUsernameFromToken(token);
|
||||
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
|
||||
}
|
||||
|
||||
|
||||
@Value("${jwt.tablet.secret}")
|
||||
private String TABLET_SECRET;
|
||||
|
||||
Reference in New Issue
Block a user