Spring Jwt 问题认证问题

问题描述 投票:0回答:1

我目前正在开发学习管理系统 (LMS) 网站的后端,并且遇到 JWT 令牌身份验证问题

使用用户名成功登录系统后 密码,我毫无问题地获得了 JWT 令牌

但是,当我尝试使用此 JWT 令牌进行身份验证时,我始终收到“禁止”错误。

@Configuration
@RequiredArgsConstructor
public class SecurityConfig {

    private final AccUserDetailsService userService;
    private final JwtAuthenticationTokenFilter filterService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .requestMatchers("api/staff/**").hasAnyRole("STAFF","ADMIN")
                .requestMatchers("api/student/**").hasRole("STUDENT")
                .anyRequest().authenticated());
        http.addFilterBefore(filterService, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web.ignoring().requestMatchers("/logging", "/welcome","api/signup","/api/authenticate");
    }

}

这是我的安全配置类

@Configuration
public class JwtAuthenticationProvider {
    @Value("${api.jwtSecret}")
    private String secret;

    private final int TOKEN_VALIDITY = 5 * 60 * 60;

    public String generateToken(String userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return doGenerateToken(claims, userDetails);
    }

    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() + TOKEN_VALIDITY * 1000))
                .signWith(getSigningKey(),SignatureAlgorithm.HS256).compact();

    }

    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    private Key getSigningKey() {
        byte[] keyBytes = Decoders.BASE64.decode(secret);
        return Keys.hmacShaKeyFor(keyBytes);
    }

    private Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    private Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

    private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);

    }

    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));

    }

}

这是我的 jwtconfiguration 类

@Component
@RequiredArgsConstructor
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    private final JwtAuthenticationProvider tokenService;
    private final AccUserDetailsService accUserDetailsService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        final String authorizationHeader = request.getHeader("Authorization");
        String username = null;
        String jwt = null;

        if(authorizationHeader != null && authorizationHeader.startsWith("Bearer ")){
            jwt = authorizationHeader.substring(7);
            username = tokenService.getUsernameFromToken(jwt);
        }
        if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){
            UserDetails userDetails = this.accUserDetailsService.loadUserByUsername(username);
            if(tokenService.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);
    }
}

这里提供过滤服务

@RestController
@RequiredArgsConstructor
public class TestController {

    private final AccountService accountService;
    private final AuthService authService;
    
    @GetMapping("/api/admin/")
    public String admin(){
        return ("<h1>Welcome admin<h1>");
    }

    @PostMapping("/api/signup")
    public String createAccount(@RequestBody SignUpRequest signUpRequest){
        accountService.signup(signUpRequest);
        return "test";
    }

    @PostMapping("/api/authenticate")
    public ResponseEntity<APIResponse<?>> createAccount(@RequestBody LoginRequest loginRequest) throws AuthenticationException {
        LoginResponse loginResponse = authService.userAuthenticate(loginRequest);
        return ResponseEntity.ok(new APIResponse<>(ResponseCode.SUCCESS_LOGIN,loginResponse));
    }
    
}

控制器类

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.dsm</groupId>
    <artifactId>dsm</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dsm</name>
    <description>Driving </description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mariadb.jdbc</groupId>
            <artifactId>mariadb-java-client</artifactId>
            <version>3.1.2</version>
        </dependency>
        <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>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <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>
            </dependency>
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt-jackson</artifactId>
                <version>0.11.5</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <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>

</project>

我已经检查了我的代码库和配置,但仍然无法解决问题。如果有人有使用 Java 和 Spring 版本的特定组合的经验,我非常感谢您帮助解决此问题。

java spring-boot spring-security jwt
1个回答
0
投票

您的

UserDetails
课程包含权威。

您正在与您的

UsernamePasswordAuthenticationToken
当局一起使用
UserDetails

如果您将其设置在您的

SecurityContextHolder
中。

尝试使用

hasAuthority
hasAnyAuthority
代替
hasRole
hasAnyRole

.requestMatchers("api/student/**").hasAuthority("STUDENT") 
                .requestMatchers("api/staff/**").hasAnyAuthority("STAFF","ADMIN")

希望有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.