代码之家  ›  专栏  ›  技术社区  ›  Buddhima Chamaranga

Spring Jwt问题身份验证问题

  •  0
  • Buddhima Chamaranga  · 技术社区  · 1 年前

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

    when try to log in to

    使用用户名和成功登录系统后 密码,我获得了JWT令牌,没有任何问题

    i get a forbidden here

    然而,当我尝试使用此JWT令牌进行身份验证时,我总是收到一个“Forbidden”错误。

    @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版本的这种特定组合有经验,我非常感谢您帮助解决这个问题。

    1 回复  |  直到 1 年前
        1
  •  1
  •   Ajaj Ali    1 年前

    你的 UserDetails 类包含权限。

    您正在使用 UsernamePasswordAuthenticationToken 用你的 用户详细信息 当局。

    如果您将其设置在 SecurityContextHolder .

    尝试使用 hasAuthority hasAnyAuthority 而不是 hasRole hasAnyRole .

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

    确保你的角色喜欢 STUDENT , STAFF 包含在您的 UserDetails's 当局。

    希望能有所帮助。