我正在使用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();
假设某些方法只能由超级用户使用,而其他方法只能由任何用户使用,那么当用户名和密码由客户端发送时,我如何区分它们?
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);
有两件事我们需要解决
为了进行身份验证和授权,我们需要一个存储以下映射的数据存储:
这里,第一个映射是身份验证所必需的,另外两个映射用于授权。
另外,请注意,我们需要对每个API调用进行身份验证和授权。因此,我们将执行大量读取操作。
因此,通常使用目录服务器或Ldap服务器(例如Apache DS)来存储这些映射,因为目录服务器是读取优化的数据存储。
在RESTful应用程序中,通常使用过滤器从请求头中提取用户名和密码,并使用Ldap服务器进行身份验证。如果认证成功,下一步是通过查询用户-角色和角色-权限映射,从Ldap服务器提取用户的权限。如果用户得到授权,只有在这种情况下,控制才会流向实际的API业务逻辑。
有关详细信息,请参阅此答案。
我知道我可以使用注释@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()));
}
}
你在这里做的是:
用户
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 安全性”部分下找到此信息。
另请参见:
我目前使用的是球衣 我现在要做的是设置泽西,这样当查询参数进来时(比如缩进),我可以告诉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扩展的