我有一个问题与 JWT 认证令牌。当我第一次用postman测试登录时,它给了我令牌,但在重新启动intelij后,我在postman和intelij中得到了403禁止错误(JWT签名与本地计算的签名不匹配。JWT的有效性不能Assert,也不应该被信任。)(这里我用 Postman)。这是我的代码
package com.example.demo.Configiration;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@Component
public class JwtUtils {
private String Secret = "671491AE98362741F722202EED3288E8FF2508B35315ADBF75EEB3195A926B40";
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
public Boolean hasClaim(String token, String claimName) {
final Claims claims = extractAllClaims(token);
return claims.get(claimName) != null;
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return c
在此处键入
laimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(Secret).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
public String generateToken(UserDetails userDetails){
Map<String,Object> claims=new HashMap<>();
return createToken(claims,userDetails);
}
public String generateToken(UserDetails userDetails,Map<String,Object> claims){
return createToken(claims,userDetails);
}
private String createToken(Map<String,Object> claims,UserDetails userDetails){
return Jwts.builder().setClaims(claims).setSubject(userDetails.getUsername())
.claim("authorities",userDetails.getAuthorities())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(24)))
.signWith(SignatureAlgorithm.HS256,Secret).compact();
}
public Boolean isTokenValide(String token, UserDetails userDetails) {
final String userName = extractUsername(token);
return (userName.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
/* private Key getSigningKey() {
byte[] keyBytes= Decoders.BASE64.decode(Secret);
return Keys.hmacShaKeyFor(keyBytes);
}*/
}
package com.example.demo.Configiration;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity
@RequiredArgsConstructor
@Configuration
public class SecurityConfig {
private final JwtAuthFilter jwtAuthFilter;
private final AuthenticationProvider authenticationProvider;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.authorizeRequests()
.requestMatchers("/hello/login")
.permitAll()
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
}
package com.example.demo.Configiration;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
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.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;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
@Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
private final UserDetailsService userDetailsService;
private final JwtUtils jwtUtils;
private final Dto dto;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
final String authHeader=request.getHeader(AUTHORIZATION);
final String userEmail;
final String jwtToken;
if (authHeader==null || !authHeader.startsWith("Bearer")){
filterChain.doFilter(request,response);
return;
}
jwtToken=authHeader.substring(7);
userEmail=jwtUtils.extractUsername(jwtToken);
if (userEmail !=null && SecurityContextHolder.getContext().getAuthentication()==null){
UserDetails userDetails=dto.findUserbyemail(userEmail);
// final Boolean isTokenValid;
if (jwtUtils.isTokenValide(jwtToken,userDetails)){
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=
new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request,response);
}
}
package com.example.demo.Configiration;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Repository
public class Dto {
private final static List<UserDetails> APPLICATION_USERS= Arrays.asList(
new User(
"[email protected]",
"aymen",
Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN"))
),
new User(
"[email protected]",
"messikh",
Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"))
)
);
public UserDetails findUserbyemail(String email){
return APPLICATION_USERS
.stream().filter(u -> u.getUsername().equals(email))
.findFirst().orElseThrow(() -> new UsernameNotFoundException("No user was found"));
}
}
package com.example.demo.Configiration;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class AppConfig {
private final Dto dto;
@Bean
public AuthenticationProvider authenticationProvider() {
final DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService());
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return daoAuthenticationProvider;
}
@Bean
public PasswordEncoder passwordEncoder() {
// return NoOpPasswordEncoder.getInstance();
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService() {
return new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
return dto.findUserbyemail(email);
}
};
}
@Bean
public AuthenticationManager authenticationManager (AuthenticationConfiguration configuration) throws Exception
{
return configuration.getAuthenticationManager();
}
}
package com.example.demo;
import lombok.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AuthentificationRequest {
private String email;
private String password;
}
package com.example.demo.Controller;
import com.example.demo.AuthentificationRequest;
import com.example.demo.Configiration.Dto;
import com.example.demo.Configiration.JwtUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/hello")
@RequiredArgsConstructor
public class Hello {
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
private final JwtUtils jwtUtils;
private final Dto dto;
@GetMapping("/hello1")
public ResponseEntity<String> hello1(){
return ResponseEntity.ok("aaaaaaaaaaaaaaaa");
}
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody AuthentificationRequest request){
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getEmail(),request.getPassword())
);
final UserDetails user=dto.findUserbyemail(request.getEmail());
if (user!=null){
return ResponseEntity.ok(jwtUtils.generateToken(user));
}
return ResponseEntity.status(400).body("ssssssssss");
}
}
4.0.0 org.springframework. Boot spring- Boot -starter-parent 3.0.6 com.example demo 2 0.0.1-SNAPSHOT demo 2 demo 2<java.version>17</java.version> org.springframework. Boot spring- Boot -starter-web org.springframework. Boot spring- Boot -starter-security
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
1条答案
按热度按时间z4iuyo4d1#
问题可能来自以下事实:您正在使用
.signWith(SignatureAlgorithm.HS256,Secret)
对令牌进行签名,并且为了在extractAllClaims
中获得声明,您仅直接使用机密,因此它无法检索适当的信息来验证令牌Jwts.parser().setSigningKey(Secret).parseClaimsJws(token).getBody();
另外,我想指出的是,根据文档,您用于签署令牌的方法已被弃用,请查看文档/Parser Doc,您可以进行适当的调整。同样作为参考,你可以把静态秘密检查为byte[],Key或String?