JSON Web 令牌 (JWT):我应该使用响应标头还是正文进行令牌传输?

Posted

技术标签:

【中文标题】JSON Web 令牌 (JWT):我应该使用响应标头还是正文进行令牌传输?【英文标题】:JSON Web Token (JWT): should I use response header or body for token transportation? 【发布时间】: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());
    


【问题讨论】:

【参考方案1】:

它是所有 api 都遵循的 HTTP 标准的一部分。基本上,想出一套每个人都遵循的规则,这样当人们开发服务器或客户端时,他们就可以遵循这套规则以避免差异

RFC https://www.rfc-editor.org/rfc/rfc7235#section-4.2

“授权”标头字段允许用户代理进行身份验证 本身带有源服务器——通常但不一定是在之后 收到 401(未经授权)响应。它的价值包括 包含用户身份验证信息的凭据 被请求资源领域的代理。

 Authorization = credentials

人们现在可以使用许多不同类型的授权标头,一旦您使用它,您就会知道会发生什么。这是一个简单的列表来展示一些

       •    Basic Auth
       •    Bearer Token
       •    API Key
       •    Digest Auth
       •    Oauth 2.0
       •    Hawk Authentication
       •    AWS Signature

【讨论】:

以上是关于JSON Web 令牌 (JWT):我应该使用响应标头还是正文进行令牌传输?的主要内容,如果未能解决你的问题,请参考以下文章

为啥要使用环境变量对 JSON Web 令牌 (JWT) 进行签名?

如何在 C# AspNetCore 网站中使用 JWT JSON Web 令牌?

JSON Web 令牌 - 如何识别用户?

我应该在哪里存储“非单页”前端应用程序的 JSON Web 令牌

使用 REST 和 JSON Web Token 上传/下载文件

如何存储 JWT refreshToken cookie 响应