【发布时间】:2020-12-24 21:50:35
【问题描述】:
我正在开发一个 RESTful Web 服务,它以 JSON Web 令牌 (JWT) 的形式发布访问令牌,以便客户端可以使用它们进行进一步授权。目前,我将令牌存储在响应正文中,但通常建议将其添加到 Authorization 标头中。为什么我应该选择标题而不是响应正文?使用一种方法比另一种方法有什么主要优势吗?
@RestController
@RequestMapping(path = "/auth", produces = "application/json")
public class AccessTokenController {
@Value("${jwt.secret.key.gen}")
private String secretKey;
@Value("${jwt.expiration.days}")
private int expirationDays;
private final UsersRepository usersRepository;
private final PasswordEncoder passwordEncoder;
@Autowired
public AccessTokenController(UsersRepository usersRepository, PasswordEncoder passwordEncoder) {
this.usersRepository = usersRepository;
this.passwordEncoder = passwordEncoder;
}
@PostMapping(value = "/access-token", consumes = "application/json")
ResponseEntity<Object> getAccessToken(@RequestBody Map<String, String> credentials) {
// #1: check request body for username and password
String username = credentials.get("username");
String password = credentials.get("password");
if (username.isBlank() || password.isBlank())
throw new IllegalArgumentException();
// #2: check database for given username and password
User user = usersRepository.findByUsername(username)
.filter(u -> passwordEncoder.matches(password, u.getPassword()))
.orElseThrow(() -> new BadCredentialsException("No such user with given password"));
// #3: check 'enabled' status for the requested user
if (!user.isEnabled())
throw new DisabledException("User is currently disabled");
// # 4: create and return access-token (finally!)
String token = Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + expirationDays * 24 * 60 * 60 * 1000))
.signWith(SignatureAlgorithm.HS512, secretKey.getBytes())
.compact();
return new ResponseEntity<>(Collections.singletonMap("access-token", token),
HttpStatus.OK);
}
@ExceptionHandler({JsonParseException.class, NullPointerException.class, IllegalArgumentException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> handleWrongOrMissingCredentials() {
return Collections.singletonMap("error", "Wrong or missing credentials");
}
@ExceptionHandler(AuthenticationException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public Map<String, String> handleAuthenticationException(AuthenticationException ex) {
return Collections.singletonMap("error", ex.getMessage());
}
}
【问题讨论】: