使用JAX-RS和Jersey进行基于REST令牌的身份验证的最佳实践

本文介绍了如何在JAX-RS 2.0(如Jersey)框架下实现基于令牌的身份验证。详细阐述了基于令牌的身份验证的工作原理,包括用户验证、令牌提取与验证、REST端点保护、识别当前用户以及支持基于角色的授权。同时,探讨了使用JWT(JSON Web Tokens)进行令牌管理的方法,如令牌刷新和撤销。此外,还讨论了如何利用JSR-250注解进行权限管理。
摘要由CSDN通过智能技术生成

本文翻译自:Best practice for REST token-based authentication with JAX-RS and Jersey

I'm looking for a way to enable token-based authentication in Jersey. 我正在寻找一种在Jersey中启用基于令牌的身份验证的方法。 I am trying not to use any particular framework. 我试图不使用任何特定的框架。 Is that possible? 那可能吗?

My plan is: A user signs up for my web service, my web service generates a token, sends it to the client, and the client will retain it. 我的计划是:用户注册我的Web服务,我的Web服务生成令牌,将其发送到客户端,客户端将保留它。 Then the client, for each request, will send the token instead of username and password. 然后,对于每个请求,客户端将发送令牌而不是用户名和密码。

I was thinking of using a custom filter for each request and @PreAuthorize("hasRole('ROLE')") but I just thought that this causes a lot of requests to the database to check if the token is valid. 我正在考虑为每个请求使用自定义过滤器和@PreAuthorize("hasRole('ROLE')")但我只是认为这会导致很多请求数据库检查令牌是否有效。

Or not create filter and in each request put a param token? 或者不创建过滤器并在每个请求中放置一个参数令牌? So that each API first checks the token and after executes something to retrieve resource. 这样每个API首先检查令牌,然后执行一些东西来检索资源。


#1楼

参考:https://stackoom.com/question/1oLwR/使用JAX-RS和Jersey进行基于REST令牌的身份验证的最佳实践


#2楼

How token-based authentication works 基于令牌的身份验证的工作原理

In token-based authentication, the client exchanges hard credentials (such as username and password) for a piece of data called token . 在基于令牌的身份验证中,客户端为称为令牌的数据交换硬凭证 (例如用户名和密码)。 For each request, instead of sending the hard credentials, the client will send the token to the server to perform authentication and then authorization. 对于每个请求,客户端不会发送硬凭证,而是将令牌发送到服务器以执行身份验证然后授权。

In a few words, an authentication scheme based on tokens follow these steps: 简而言之,基于令牌的身份验证方案遵循以下步骤:

  1. The client sends their credentials (username and password) to the server. 客户端将其凭据(用户名和密码)发送到服务器。
  2. The server authenticates the credentials and, if they are valid, generate a token for the user. 服务器验证凭据,如果它们有效,则为用户生成令牌。
  3. The server stores the previously generated token in some storage along with the user identifier and an expiration date. 服务器将先前生成的令牌与用户标识符和到期日期一起存储在一些存储器中。
  4. The server sends the generated token to the client. 服务器将生成的令牌发送到客户端。
  5. The client sends the token to the server in each request. 客户端在每个请求中将令牌发送到服务器。
  6. The server, in each request, extracts the token from the incoming request. 每个请求中的服务器从传入请求中提取令牌。 With the token, the server looks up the user details to perform authentication. 使用令牌,服务器查找用户详细信息以执行身份验证。
    • If the token is valid, the server accepts the request. 如果令牌有效,则服务器接受该请求。
    • If the token is invalid, the server refuses the request. 如果令牌无效,则服务器拒绝该请求。
  7. Once the authentication has been performed, the server performs authorization. 一旦执行了身份验证,服务器就会执行授权。
  8. The server can provide an endpoint to refresh tokens. 服务器可以提供端点来刷新令牌。

Note: The step 3 is not required if the server has issued a signed token (such as JWT, which allows you to perform stateless authentication). 注意:如果服务器已发出签名令牌(例如JWT,允许您执行无状态身份验证),则不需要执行步骤3。

What you can do with JAX-RS 2.0 (Jersey, RESTEasy and Apache CXF) 使用JAX-RS 2.0(Jersey,RESTEasy和Apache CXF)可以做些什么

This solution uses only the JAX-RS 2.0 API, avoiding any vendor specific solution . 此解决方案仅使用JAX-RS 2.0 API, 避免任何特定于供应商的解决方案 So, it should work with JAX-RS 2.0 implementations, such as Jersey , RESTEasy and Apache CXF . 因此,它应该适用于JAX-RS 2.0实现,例如JerseyRESTEasyApache CXF

It is worthwhile to mention that if you are using token-based authentication, you are not relying on the standard Java EE web application security mechanisms offered by the servlet container and configurable via application's web.xml descriptor. 值得一提的是,如果使用基于令牌的身份验证,则不依赖于servlet容器提供的标准Java EE Web应用程序安全机制,并且可以通过应用程序的web.xml描述符进行配置。 It's a custom authentication. 这是一种自定义身份验证。

Authenticating a user with their username and password and issuing a token 使用用户名和密码验证用户并发出令牌

Create a JAX-RS resource method which receives and validates the credentials (username and password) and issue a token for the user: 创建一个JAX-RS资源方法,该方法接收并验证凭据(用户名和密码)并为用户发出令牌:

@Path("/authentication")
public class AuthenticationEndpoint {

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Response authenticateUser(@FormParam("username") String username, 
                                     @FormParam("password") String password) {

        try {

            // Authenticate the user using the credentials provided
            authenticate(username, password);

            // Issue a token for the user
            String token = issueToken(username);

            // Return the token on the response
            return Response.ok(token).build();

        } catch (Exception e) {
            return Response.status(Response.Status.FORBIDDEN).build();
        }      
    }

    private void authenticate(String username, String password) throws Exception {
        // Authenticate against a database, LDAP, file or whatever
        // Throw an Exception if the credentials are invalid
    }

    private String issueToken(String username) {
        // Issue a token (can be a random String persisted to a database or a JWT token)
        // The issued token must be associated to a user
        // Return the issued token
    }
}

If any exceptions are thrown when validating the credentials, a response with the status 403 (Forbidden) will be returned. 如果在验证凭据时抛出任何异常,将返回状态为403 (Forbidden)的响应。

If the credentials are successfully validated, a response with the status 200 (OK) will be returned and the issued token will be sent to the client in the response payload. 如果成功验证凭据,将返回状态为200 (OK)的响应,并且已发布的令牌将在响应有效负载中发送到客户端。 The client must send the token to the server in every request. 客户端必须在每个请求中将令牌发送到服务器。

When consuming application/x-www-form-urlencoded , the client must to send the credentials in the following format in the request payload: 在使用application/x-www-form-urlencoded ,客户端必须在请求有效负载中以以下格式发送凭据:

username=admin&password=123456

Instead of form params, it's possible to wrap the username and the password into a class: 而不是形式参数,可以将用户名和密码包装到类中:

public class Credentials implements Serializable {

    private String username;
    private String password;

    // Getters and setters omitted
}

And then consume it as JSON: 然后将其作为JSON使用:

@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response authenticateUser(Credentials credentials) {

    String username = credentials.getUsername();
    String password = credentials.getPassword();

    // Authenticate the user, issue a token and return a response
}

Using this approach, the client must to send the credentials in the following format in the payload of the request: 使用此方法,客户端必须在请求的有效负载中以以下格式发送凭据:

{
  "username": "admin",
  "password": "123456"
}

Extracting the token from the request and validating it 从请求中提取令牌并验证它

The client should send the token in the standard HTTP Authorization header of the request. 客户端应该在请求的标准HTTP Authorization标头中发送令牌。 For example: 例如:

Authorization: Bearer <token-goes-here>

The name of the standard HTTP header is unfortunate because it carries authentication information, not authorization . 标准HTTP标头的名称很不幸,因为它带有身份验证信息,而不是授权 However, it's the standard HTTP header for sending credentials to the server. 但是,它是用于将凭据发送到服务器的标准HTTP标头。

JAX-RS provides @NameBinding , a meta-annotation used to create other annotations to bind filters and interceptors to resource classes and methods. JAX-RS提供@NameBinding ,这是一个元注释,用于创建其他注释以将过滤器和拦截器绑定到资源类和方法。 Define a @Secured annotation as following: 定义@Secured注释如下:

@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Secured { }

The above defined name-binding annotation will be used to decorate a filter class, which implements ContainerRequestFilter , allowing you to intercept the request before it be handled by a resource method. 上面定义的名称绑定注释将用于修饰过滤器类,该类实现ContainerRequestFilter ,允许您在资源方法处理请求之前拦截请求。 The ContainerRequestConte

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值