English 中文(简体)
为什么在阅读和通过附有有效签名的授权时会出现401个未经许可的错误?
原标题:Why does a 401 Unauthorized error occur when an authorization token with a valid signature is read and passed?

我正与春布特和React合作,认证和授权用户,然后进入安全终点。

The API creates a token when a login request is made and then decodes it:

package com.example.demo.service;
import java.security.Key;
import java.util.Date;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import jakarta.xml.bind.DatatypeConverter;

@Service
public class JwTTokenProviderService {
    
    @Value("${jwt.secret}")
    private String JWT_SECRET_KEY;

        // the JWT_SECRET_KEY is populated in the application.properties file.
    
    public String generateToken(String username, String role) {
        
        //The JWT signature algorithm we will be using to sign the token
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        
        Key signingKey = new SecretKeySpec(DatatypeConverter.parseBase64Binary(JWT_SECRET_KEY), signatureAlgorithm.getJcaName());
        long jwtExpirationInMs = 36000;
        
        System.out.println("Username at generating token is " + username);
        System.out.println("Role at generating token is " + role);
        
        return Jwts.builder()
                .setSubject(username)
                .claim("hasRole", role)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + jwtExpirationInMs))
                .signWith(signingKey, signatureAlgorithm)
                .compact();
        
    }
    
    public String getAllClaimsFromToken(String token) {
        
        System.out.println("Token at getAllClaimsFromToken is " + token);
        
        try {
            
            byte[] arrSecret = DatatypeConverter.parseBase64Binary(JWT_SECRET_KEY);
            Key signingKey = new SecretKeySpec(arrSecret, SignatureAlgorithm.HS256.getJcaName());
             Jws<Claims> jwsClaims = Jwts.parser()
                     .setSigningKey(signingKey)
                     .parseClaimsJws(token);

                    Claims claims = jwsClaims.getBody();
                    return claims.get("hasRole", String.class); //
        
        } catch (Exception e) {
            System.out.println("Could not get all claims TOken from passed token");
            System.out.println("Exception is " + e);
            return null;
        }
        
        
    }

}

这是发出请求的方法:

    getInfoForUser(username) {
        
        try {
            
            console.log("Username at Axios is, ", username)
            
            console.log("User token at getInfoForUser is: ", localStorage.getItem( userToken ))
            
            return axios.post("http://myserver:8080/myapp/login/get-info-for-user", {params: {
                    username: username
                },
                headers: {
                   Content-Type : application/json; charset=UTF-8 ,
                       Authorization : ......Bearer ${localStorage.getItem("userToken")}......,
                   Accept :  application/json 
                }}
                )
            
            
        } catch (error) {
            
            console.log("Error is, ", error)
        }
    }

这是控制器的附担保方法:

    @PreAuthorize("hasRole( ROLE_USER )")
    @PostMapping("/get-info-for-user")
    public Object[] getInfoForUser(@Param("username") String username) {
        
        return userService.getInfoForUser(username);
    }

之后,这又产生了一个回头角,但是,这预示着问题,因为它在实施象征性机制之前运作。

The JwtResponse file, or model for the authorization header:

package com.example.demo.model;

import java.util.List;

public class JwtResponse {
    
    private String token;
    private String type = "Bearer";

    private String username;
    private String hasRole;
    public String getToken() {
        return token;
    }
    public void setToken(String token) {
        this.token = token;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String gethasRole() {
        return hasRole;
    }
    public void sethasRole(String hasRole) {
        this.hasRole = hasRole;
    }
    public JwtResponse(String token, String username, String hasRole) {
        super();
        this.token = token;
    
        this.username = username;
        this.hasRole = hasRole;
    }

}

5. 安保考虑使说明能够:

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {

    //...

}

参考需要:

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

This is the feedback once the user logs in:

“entergraph

用户名称、作用、标注和类型“Bearer”都是通过的,然后在附担保的终端点要求中作为授权负责人提交这一信息。

在我从申请中输入秘密后,还核实了该标的。 财产档案:

enter image description here

The request being sent: enter image description here

And the response: enter image description here

It is the first time I am attempting to do this and generally speaking, checked over these things:

  1. Used a POST method and not GET in the frontend and @PostMapping for the backend; I ve tried switching but the result is the same.
  2. The JWT secret is secured in the application.properties file.
  3. I do get a warning that the parser() and setSigningKey() method from it are deprecated in the version of JJWT I am using, but I haven t been able to locate a good example - though that should not necessarily trigger the 401 error.
  4. Because I am using the @PreAuthorize annotation, which looks for ROLE_ as a prefix, I ve done that in the database, so it returns the same syntax.
  5. I thought about the "hasRole" attribute in the annotation and made it the same in the JwtResponse model, which builds the authorization header.
  6. I thought it was an issue with the secret being generated, as the token returned an invalid signature, but that got corrected when I put in the secret into the checker.
  7. Everything is encoded and secured and there are no plain text values as relevant to the token being passed around. Or rather, should there be nothing but the token in the authorization header of the request?
  8. Pre/Post is enabled in the security configuration.

这或许是我所看到的关于SO的最有益的指南:

法定秘密为:

任何见解都将受到赞赏......

......

问题回答




相关问题
How to use one react app into another react app?

I have two react apps, parent app and child app. and child app have an hash router. I have build the child app using npm run build, It creates build folder. That build folder moved into inside the ...

how to get selected value in Ant Design

I want to print the selected value, and below is my option list: const vesselName = [ { value: 0 , label: ALBIDDA , }, { value: 1 , label: ALRUMEILA , }, { value: 2 ,...

How to add a <br> tag in reactjs between two strings?

I am using react. I want to add a line break <br> between strings No results and Please try another search term. . I have tried No results.<br>Please try another search term. but ...

热门标签