当前位置: 首页 > 知识库问答 >
问题:

如何在泽西岛对用户进行身份验证

姜钊
2023-03-14

我正在使用Jersey用Java编写一个RESTful应用程序,我需要对用户进行身份验证。我知道我可以使用注释@RolesAllowed来指定资源中的角色,但是我不明白用户是如何与特定角色相关联的。客户端以这种方式发送用户名和密码

    HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic(user, password);
    Client client = ClientBuilder.newClient();
    client.register(feature);
    WebTarget target = client.target(baseUrl).path(urlString);
    Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON);
    Response response = invocationBuilder.get();

假设某些方法只能由超级用户使用,而其他方法只能由任何用户使用,那么当用户名和密码由客户端发送时,我如何区分它们?

共有3个答案

周健
2023-03-14

HttpAuthenticationFeature类提供HttpBasic和Digest客户端身份验证功能。该功能在4种模式中的一种模式下工作;

BASIC:它是抢占式身份验证方式,即信息始终与每个HTTP请求一起发送。此模式必须与SSL/TLS的使用相结合,因为密码仅发送BASE64编码。

基本非抢占式:它是非抢占式身份验证方式,即仅当服务器拒绝具有401状态代码的请求,然后使用身份验证信息重复请求时,才会添加身份验证信息。

摘要:Http摘要认证。不需要使用SSL/TLS。

通用:非抢先模式下基本认证和摘要认证的组合,即在401响应的情况下,根据WWW-Authenticate HTTP报头中定义的认证请求使用适当的认证。

要使用HttpAuthenticationFeature,请构建它的实例并向客户端注册。例如;

1)基本认证模式

HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("username", "password");

final Client client = ClientBuilder.newClient();
client.register(feature);

2) 基本认证:非预想模式

HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder()
                                    .nonPreemptive()
                                    .credentials("username", "password")
                                    .build();

final Client client = ClientBuilder.newClient();
client.register(feature);

3) 通用模式

//Universal builder having different credentials for different schemes
HttpAuthenticationFeature feature = HttpAuthenticationFeature.universalBuilder()
.credentialsForBasic("username1", "password1")
.credentials("username2", "password2").build();

final Client client = ClientBuilder.newClient();
client.register(feature);
闾丘鸣
2023-03-14

有两件事我们需要解决

  1. 身份验证 - 检查用户是否确实是它声称的那个
  2. 授权 - 如果经过身份验证的用户有权访问给定的方法

为了进行身份验证和授权,我们需要一个存储以下映射的数据存储:

  1. 用户与其密码之间的映射
  2. 角色和用户之间的映射
  3. 角色和权限之间的映射

这里,第一个映射是身份验证所必需的,另外两个映射用于授权。

另外,请注意,我们需要对每个API调用进行身份验证和授权。因此,我们将执行大量读取操作。

因此,通常使用目录服务器或Ldap服务器(例如Apache DS)来存储这些映射,因为目录服务器是读取优化的数据存储。

在RESTful应用程序中,通常使用过滤器从请求头中提取用户名和密码,并使用Ldap服务器进行身份验证。如果认证成功,下一步是通过查询用户-角色和角色-权限映射,从Ldap服务器提取用户的权限。如果用户得到授权,只有在这种情况下,控制才会流向实际的API业务逻辑。

有关详细信息,请参阅此答案。

浦琪
2023-03-14

我知道我可以使用注释@RolesAllowed来指定资源中的角色,但是我不明白用户是如何与特定的角色相关联的

角色信息存储在数据库中。假设您有一个User,它对数据库中的User和ROLES表进行建模

class User {
  String username;
  List<String> roles;

  public String getUsername() { return username; }
  public void setUsername(String username) { this.username = username; }
  public List<String> getRoles() { return roles; }
  public void setRoles(List<String> roles) { this.roles = roles; }
}

您可以将< code>User放入一个Jersey过滤器中。这也是您进行身份验证的地方。

@Provider
@Priority(Priorities.AUTHENTICATION)  // needs to happen before authorization
class AuthenticationFilter implements ContainerRequestFilter {
    @Inject
    private UserService userService;  // this is your own service

    @Override
    public void filter(ContainerRequestContex context) {
        // note, this is a lazy implementation of Basic auth.
        // it doesn't do ant error checking. Please see
        // link at bottom for better imlementation
        String authzHeader = context.getHeaderString(HttpHeaders.AUTHORIZATION); // (1)
        String decoded = Base64.decodeAsString(authzHeader);
        String[] split = decoded.split(":");
        User user = userService.getUser(split[0]);                              // (2)
        if (user == null || !user.getPassword().equals(someHash(split[1])) {    // (3)
            throw new UnauthorizedException();
        }
        SecurityContext oldContext = context.getSecurityContext();               // (4)
        context.setSecurityContext(new BasicSecurityConext(user, oldContext.isSecure()));
    }
}

你在这里做的是:

  1. 分析基本身份验证授权头
  2. 使用用户名获取用户
  3. 进行身份验证
  4. 设置新的SecurityContext

< code > BasicSecurityContext 如下所示。这是您将角色与用户相关联的地方。

static class BasicSecurityContext implements SecurityContext {
   private final User user;
   private final boolean secure;
   
   public BasicSecurityContext(User user, boolean secure) {
       this.user = user;
       this.secure = secure;
   }

   @Override
   public Principal getUserPrincipal() {
       return new Principal() {
           @Override
           public String getName() {
                return user.getUsername();
           }
       };
   }

   @Override
   public String getAuthenticationScheme() {
       return SecurityContext.BASIC_AUTH;
   }

   @Override
   public boolean isSecure() { return secure; }

   @Override
   public boolean isUserInRole(String role) {
       return user.getRoles().contains(role);
   }
}

如果您查看底部的isUserInRole。Jersey将从资源方法或类中获取@RolesAllowed注释,获取值,然后将其传递给isUserInRole。如果返回true,则用户被授权。在伪代码中

@GET
@Path("/somepath")
@RolesAllowed({"USER", "SUPER_USER"})
public Response get() {}
...

RolesAllowed annotation = resourceMethod.getAnnotation(RolesAllowed.class);
String roles = annotation.value();
SecurityContext context = getSecurityContext();
for (String role: roles) {
    if (context.isUserInRole(role)) {
        return;
    }
}
throw new ForbiddenException();

这只是伪代码,但它显示了泽西岛如何处理授权,使用@RolesAllowed安全上下文,以及如何实现isUserInRole

此授权功能不会自动打开。您需要自己打开它。为此,只需注册角色允许的动态功能

public JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(RolesAllowedDynamicFeature.class);
    }
}

这里需要注意的一点是,在上述所有内容中,我们正在实现我们的基本身份验证和安全上下文的设置。这并没有什么真正的问题。但是如果您使用servlet容器身份验证机制,泽西实际上会从HttpServletRequest获取身份验证信息。HttpServletRequest有一个getUser主体()方法和一个isUserInRole方法。泽西将使用这些在SecurityContext中委派。因此,如果您是容器身份验证的用户,那么您真的不需要实现任何东西。您只需要注册RolesAlloweDynamicFeature

如果要使用容器的身份验证机制,应查阅服务器的文档。在服务器中设置了一个领域之后,您将需要使用安全信息配置 Web.xml。下面的链接中有一个示例。您还应该在 Java EE 文档的“Web 安全性”部分下找到此信息。

另请参见:

    < li >筛选器和拦截器,了解有关使用筛选器的更多信息。 < li>Security,了解有关在泽西岛使用安全措施的更多信息。 < li >基本身份验证过滤器的更好实现 < Li > Jersey 2中的ResourceConfig类到底是什么?
 类似资料:
  • 我目前使用的是球衣 我现在要做的是设置泽西,这样当查询参数进来时(比如缩进),我可以告诉Jackson以“更漂亮的格式,也就是缩进”序列化JSON。您可以通过使用SerializationConfig.Feature.INDENT_OUTPUT配置JSON映射器来轻松地告诉Jackson这样做。 问题是,我如何在每个请求的基础上获取一个queryparam并使用它来修改Jackson的输出?

  • 问题内容: 我正在尝试编写一个使用Jersey客户端API访问RESTful Web服务的库。该服务需要设置cookie的登录请求,然后后续请求必须将该cookie设置为成功。登录请求按预期方式工作,我能够从登录响应中检索cookie,但似乎无法在后续请求中重新添加cookie。谁能说出我可能做错了什么。这是发出请求的代码: 当请求没有失败时,服务将以应用程序错误“ No Session”进行响应

  • null 我研究了OAuth2隐式授权,但它要求用户在成功验证后批准/拒绝应用程序。它在我的情况下不起作用,因为我同时拥有应用程序和API。 我查看了OAuth2密码授权,它并不完美,因为我需要公开client_id/client_secret。 我关注OAuth2的原因是因为该API最终将是公开的。 忘记OAuth2,在用户发布用户名/密码时手动生成access_token(在本例中,当API公

  • 我有一个正在运行的Web服务,它将被客户端移动应用程序使用。其中一项服务是返回一个JSON对象数组(超过1000个对象),每个对象都有相当大的大小。服务器端的整个计算需要一些时间,这不是一个好的用户体验。所以我希望以块的形式发送数据,例如每个块10个对象,这样这些数据就会占据屏幕,当他滚动时,或者当数据准备好时,屏幕上充满了从最新收到的块中新获取的数据。 我使用Jersey框架并发送一个Java<

  • 问题内容: 解析服务器提供OAuth身份验证。如何使用Parse Server的预定义OAuth模块(例如Facebook)来注册新用户或登录“ _User”类的现有用户? Parse Server 文档提供了有关如何配置OAuth模块的示例。但是,如何在iOS项目中使用它来登录或注册用户? 问题答案: 1,创建一个从NSObject和PFUserAuthenticationDelegate扩展的