首页 > 解决方案 > 尝试使用 jwt 从反应登录 api 时出现 401 状态

问题描述

我正在尝试从反应应用程序登录 API,但我不断收到相同的 401 错误。我的 Spring Boot 控制台中的警告是:

2018-07-06 10:35:15.623  WARN 20328 --- [nio-8080-exec-1] c.s.s.JwtAuthorizationTokenFilter        : couldn't find bearer string, will ignore the header

我的反应控制台中的错误是:

POST http://localhost:8080/api/user 401 ()
Login._this.handleSubmit @ Login.js:48
callCallback @ react-dom.development.js:100
invokeGuardedCallbackDev @ react-dom.development.js:138
invokeGuardedCallback @ react-dom.development.js:187
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:201
executeDispatch @ react-dom.development.js:461
executeDispatchesInOrder @ react-dom.development.js:483
executeDispatchesAndRelease @ react-dom.development.js:581
executeDispatchesAndReleaseTopLevel @ react-dom.development.js:592
forEachAccumulated @ react-dom.development.js:562
runEventsInBatch @ react-dom.development.js:723
runExtractedEventsInBatch @ react-dom.development.js:732
handleTopLevel @ react-dom.development.js:4476
batchedUpdates$1 @ react-dom.development.js:16659
batchedUpdates @ react-dom.development.js:2131
dispatchEvent @ react-dom.development.js:4555
interactiveUpdates$1 @ react-dom.development.js:16714
interactiveUpdates @ react-dom.development.js:2150
dispatchInteractiveEvent @ react-dom.development.js:4532
Login.js:61 RESPONSE undefined
Login.js:48 Fetch failed loading: POST "http://localhost:8080/api/user".

我看到我没有得到回应,但我不知道为什么。任何帮助,将不胜感激。谢谢!

这是我的登录组件。

class Login extends Component {

    state={
            username:'',
            password: ''
    };

    handleSubmit = event => {
        event.preventDefault();


        return fetch(API_BASE_URL+"/user", {
        method: 'POST',
        headers: {
            'Accept':'application/json',
            'Content-Type':'application/json'},
         body:JSON.stringify({
             'username': this.state.username,
             'password':this.state.password
         })
        })
        .then((response) => {
                response.json();
                localStorage.setItem(TOKEN_KEY, response.accessToken);
                console.log("RESPONSE", response.data);
        })
        .catch(error =>{
            console.log("ERROR: ", error);
        });
    }
}

这是我的用户控制器:

public class UserController {


@Value("${jwt.header}")
private String tokenHeader;

@Autowired
private JwtTokenUtil jwtTokenUtil;

@Autowired
@Qualifier("jwtUserDetailsService")
private UserDetailsService userDetailsService;

@RequestMapping(value = "/api/user", method = RequestMethod.GET)
public JwtUser getAuthenticatedUser(HttpServletRequest request) {
    String token = request.getHeader(tokenHeader).substring(7);
    String username = jwtTokenUtil.getUsernameFromToken(token);
    JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username);
    return user;
}

}

AuthenticationRestController 文件:

public class AuthenticationRestController {

@Value("${jwt.header}")
private String tokenHeader;

@Autowired
private AuthenticationManager authenticationManager;

@Autowired
private JwtTokenUtil jwtTokenUtil;

@Autowired
PasswordEncoder passwordEncoder;

@Autowired
@Qualifier("jwtUserDetailsService")
private UserDetailsService userDetailsService;

@Autowired
private SocialJUserRepository userRepository;

@RequestMapping(value = "${jwt.route.authentication.path}", method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtAuthenticationRequest authenticationRequest) throws AuthenticationException {

    authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());

    // Reload password post-security so we can generate the token
    final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
    final String token = jwtTokenUtil.generateToken(userDetails);

    // Return the token
    return ResponseEntity.ok(new JwtAuthenticationResponse(token));
}

@RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.GET)
public ResponseEntity<?> refreshAndGetAuthenticationToken(HttpServletRequest request) {
    String authToken = request.getHeader(tokenHeader);
    final String token = authToken.substring(7);
    String username = jwtTokenUtil.getUsernameFromToken(token);
    JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username);

    if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())) {
        String refreshedToken = jwtTokenUtil.refreshToken(token);
        return ResponseEntity.ok(new JwtAuthenticationResponse(refreshedToken));
    } else {
        return ResponseEntity.badRequest().body(null);
    }
}

@ExceptionHandler({AuthenticationException.class})
public ResponseEntity<String> handleAuthenticationException(AuthenticationException e) {
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage());
}

/**
 * Authenticates the user. If something is wrong, an {@link AuthenticationException} will be thrown
 */
private void authenticate(String username, String password) {
    Objects.requireNonNull(username);
    Objects.requireNonNull(password);


    try {
        authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
    } catch (DisabledException e) {
        throw new AuthenticationException("User is disabled!", e);
    } catch (BadCredentialsException e) {
        throw new AuthenticationException("Bad credentials!", e);
    }
}

@RequestMapping(value = "${jwt.route.signup.path}", method = RequestMethod.POST)
public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signupRequest) {
    if(userRepository.existsByUsername(signupRequest.getUsername())) {
        return new ResponseEntity(new ApiResponse(false, "Username is already taken!"),
                HttpStatus.BAD_REQUEST);
    }

    if(userRepository.existsByEmail(signupRequest.getEmail())) {
        return new ResponseEntity(new ApiResponse(false, "Email Address already in use!"),
                HttpStatus.BAD_REQUEST);
    }

    // Creating user's account
    socialjuser user = new socialjuser(signupRequest.getFirstname(), signupRequest.getLastname(), signupRequest.getUsername(),
            signupRequest.getEmail(), signupRequest.getPassword());

    user.setPassword(passwordEncoder.encode(user.getPassword()));


    socialjuser result = userRepository.save(user);

    URI location = ServletUriComponentsBuilder
            .fromCurrentContextPath().path("/api/users/{username}")
            .buildAndExpand(result.getUsername()).toUri();

    return ResponseEntity.created(location).body(new ApiResponse(true, "User registered successfully"));
}

标签: reactjsspring-bootjwt

解决方案


您的getAuthenticatedUserAPI 只能在登录后调用。因此,handleSubmit登录组件中的方法需要调用不同的端点,如下所示:

fetch(API_BASE_URL+"/login", {
method: 'POST', // POST or GET depending on your definition inside controller
headers: {
    'Accept':'application/json',
    'Content-Type':'application/json'},
 body:JSON.stringify({
     'username': this.state.username,
     'password':this.state.password
 })
})
.then((response) => {
        response.json();
        localStorage.setItem(TOKEN_KEY, response.accessToken); //Persist
         console.log("RESPONSE", response.data);
})
.catch(error =>{
    console.log("ERROR: ", error);
});

上述调用将身份验证令牌保存在本地存储中。下一步,可以通过以下方式从您的后端获取登录用户的用户详细信息:

getUserDetails = () => {
    fetch(API_BASE_URL+"/user", {
    method: 'GET',
    headers: {
        'Authorization': `Bearer ${localStorage.getItem(TOKEN_KEY)}`,
        'Accept':'application/json',
        'Content-Type':'application/json'}
    })
    .then((response) => {
            console.log("RESPONSE", response.data); // <- Your User Details here.
    })
    .catch(error =>{
        console.log("ERROR: ", error);
    });
}

当您添加带"Bearer"前缀的授权标头时,警告应该消失,因为它正是它所说的。


推荐阅读