Jax RS授权
Jax RS Authorization
我在 class 有一个现有代码,它是从 javax.ws.rs.core.Application
扩展而来的
...
Context childContext = component.getContext().createChildContext();
JaxRsApplication application = new JaxRsApplication(childContext);
application.add(this);
application.setStatusService(new ErrorStatusService());
childContext.getAttributes().put("My Server", this);
...
ChallengeAuthenticator challengeGuard = new ChallengeAuthenticator(null, ChallengeScheme.HTTP_BASIC, "REST API Realm");
//Create in-memory users with roles
MemoryRealm realm = new MemoryRealm();
User user = new User("user", "user");
realm.getUsers().add(user);
realm.map(user, Role.get(null, "user"));
User owner = new User("admin", "admin");
realm.getUsers().add(owner);
realm.map(owner, Role.get(null, "admin"));
//Attach verifier to check authentication and enroler to determine roles
challengeGuard.setVerifier(realm.getVerifier());
challengeGuard.setEnroler(realm.getEnroler());
challengeGuard.setNext(application);
// Attach the application with HTTP basic authentication security
component.getDefaultHost().attach(challengeGuard);
我的代码中没有 web.xml。我想为我的代码添加授权。这:https://restlet.com/technical-resources/restlet-framework/guide/2.3/core/security/authorization 不适用于我,因为我没有 restlet 资源。
如何在我的代码中实现 jax rs 授权?
编辑 1: 现有代码使用 restlet JAX-RS 扩展:https://restlet.com/technical-resources/restlet-framework/guide/2.2/extensions/jaxrs
我已经在我的 jax-rs 资源上试过了 class:
@GET
@Path("/")
public String getStatus() {
if (!securityContext.isUserInRole("admin")) {
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
...
}
但是,即使我使用 admin
用户登录,它也会抛出 403。
编辑 2:
我这里查的时候:https://restlet.com/technical-resources/restlet-framework/guide/2.2/extensions/jaxrs有一段代码:
this.setRoleChecker(...); // if needed
这可能会解决我的问题,但我不知道如何设置角色检查器。
PS: 我使用 jersey 1.9 和 restlet 2.2.3.
不太清楚(至少对我来说 :-) )您要实现的目标。
如果你有一个 class,它是 javax.ws.rs.core.Application 的子class,你应该能够简单地添加 @RolesAllowed("user") 作为资源的注释 classes,如图https://jersey.java.net/documentation/latest/security.html
@Path("/")
@PermitAll
public class Resource {
@RolesAllowed("user")
@GET
public String get() { return "GET"; }
@RolesAllowed("admin")
@POST
public String post(String content) { return content; }
@Path("sub")
public SubResource getSubResource() {
return new SubResource();
}
}
访问该资源应该会提示您输入凭据。如果这不起作用,那么您需要提供一个小代码示例,它可以编译但不会执行您想要的操作。这样就更容易看出问题出在哪里以及需要做什么才能使其正常工作
您需要实施您的 RoleChecker
using this interface。
正如文档所说:
Because the Restlet API does not support its own mechanism for role checks (as e.g. the Servlet API), you must use this inteface if you need role checks in a JAX-RS application.
This interface is used to check, if a user is in a role. Implementations must be thread save.
因此,作为实施示例,您可以这样做:
public class MyRoleChecker implements RoleChecker {
public boolean isInRole(Principal principal, String role) {
return principal.getRole().equals(role);
}
}
已编辑:
另一方面,当您使用新的 API 时,您需要实现 SecurityContext
并在您的资源方法中使用 @Context 注入它。
然后你通过用户名从存储中获取角色列表。存储实现由您决定。请参考这个example
@Priority(Priorities.AUTHENTICATION)
public class AuthFilterWithCustomSecurityContext implements ContainerRequestFilter {
@Context
UriInfo uriInfo;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String authHeaderVal = requestContext.getHeaderString("Auth-Token");
String subject = validateToken(authHeaderVal); //execute custom authentication
if (subject!=null) {
final SecurityContext securityContext = requestContext.getSecurityContext();
requestContext.setSecurityContext(new SecurityContext() {
@Override
public Principal getUserPrincipal() {
return new Principal() {
@Override
public String getName() {
return subject;
}
};
}
@Override
public boolean isUserInRole(String role) {
List<Role> roles = findUserRoles(subject);
return roles.contains(role);
}
@Override
public boolean isSecure() {
return uriInfo.getAbsolutePath().toString().startsWith("https");
}
@Override
public String getAuthenticationScheme() {
return "Token-Based-Auth-Scheme";
}
});
}
}
}
我可以让它像这样工作:
申请class:
...
application.setRoles(getRoles(application));
...
public static List<Role> getRoles(JaxRsApplication application) {
List<Role> roles = new ArrayList<>();
for (AuthorizationRoleEnum authorizationRole : AuthorizationRoleEnum.values()) {
roles.add(new Role(application, authorizationRole.toString()));
}
return roles;
}
...
授权枚举:
public enum AuthorizationRoleEnum {
USER("user"),
ADMIN("admin");
private final String value;
AuthorizationRoleEnum(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
根据我的资源 classes:
...
@Context
SecurityContext securityContext;
...
allowOnlyAdmin(securityContext);
...
public void allowOnlyAdmin(SecurityContext securityContext) {
if (securityContext.getAuthenticationScheme() != null
&& !securityContext.isUserInRole(AuthorizationRoleEnum.ADMIN.toString())) {
throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN)
.entity("User does not have required " + AuthorizationRoleEnum.ADMIN + " role!").build());
}
}
...
我在 class 有一个现有代码,它是从 javax.ws.rs.core.Application
...
Context childContext = component.getContext().createChildContext();
JaxRsApplication application = new JaxRsApplication(childContext);
application.add(this);
application.setStatusService(new ErrorStatusService());
childContext.getAttributes().put("My Server", this);
...
ChallengeAuthenticator challengeGuard = new ChallengeAuthenticator(null, ChallengeScheme.HTTP_BASIC, "REST API Realm");
//Create in-memory users with roles
MemoryRealm realm = new MemoryRealm();
User user = new User("user", "user");
realm.getUsers().add(user);
realm.map(user, Role.get(null, "user"));
User owner = new User("admin", "admin");
realm.getUsers().add(owner);
realm.map(owner, Role.get(null, "admin"));
//Attach verifier to check authentication and enroler to determine roles
challengeGuard.setVerifier(realm.getVerifier());
challengeGuard.setEnroler(realm.getEnroler());
challengeGuard.setNext(application);
// Attach the application with HTTP basic authentication security
component.getDefaultHost().attach(challengeGuard);
我的代码中没有 web.xml。我想为我的代码添加授权。这:https://restlet.com/technical-resources/restlet-framework/guide/2.3/core/security/authorization 不适用于我,因为我没有 restlet 资源。
如何在我的代码中实现 jax rs 授权?
编辑 1: 现有代码使用 restlet JAX-RS 扩展:https://restlet.com/technical-resources/restlet-framework/guide/2.2/extensions/jaxrs
我已经在我的 jax-rs 资源上试过了 class:
@GET
@Path("/")
public String getStatus() {
if (!securityContext.isUserInRole("admin")) {
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
...
}
但是,即使我使用 admin
用户登录,它也会抛出 403。
编辑 2:
我这里查的时候:https://restlet.com/technical-resources/restlet-framework/guide/2.2/extensions/jaxrs有一段代码:
this.setRoleChecker(...); // if needed
这可能会解决我的问题,但我不知道如何设置角色检查器。
PS: 我使用 jersey 1.9 和 restlet 2.2.3.
不太清楚(至少对我来说 :-) )您要实现的目标。 如果你有一个 class,它是 javax.ws.rs.core.Application 的子class,你应该能够简单地添加 @RolesAllowed("user") 作为资源的注释 classes,如图https://jersey.java.net/documentation/latest/security.html
@Path("/")
@PermitAll
public class Resource {
@RolesAllowed("user")
@GET
public String get() { return "GET"; }
@RolesAllowed("admin")
@POST
public String post(String content) { return content; }
@Path("sub")
public SubResource getSubResource() {
return new SubResource();
}
}
访问该资源应该会提示您输入凭据。如果这不起作用,那么您需要提供一个小代码示例,它可以编译但不会执行您想要的操作。这样就更容易看出问题出在哪里以及需要做什么才能使其正常工作
您需要实施您的 RoleChecker
using this interface。
正如文档所说:
Because the Restlet API does not support its own mechanism for role checks (as e.g. the Servlet API), you must use this inteface if you need role checks in a JAX-RS application. This interface is used to check, if a user is in a role. Implementations must be thread save.
因此,作为实施示例,您可以这样做:
public class MyRoleChecker implements RoleChecker {
public boolean isInRole(Principal principal, String role) {
return principal.getRole().equals(role);
}
}
已编辑:
另一方面,当您使用新的 API 时,您需要实现 SecurityContext
并在您的资源方法中使用 @Context 注入它。
然后你通过用户名从存储中获取角色列表。存储实现由您决定。请参考这个example
@Priority(Priorities.AUTHENTICATION)
public class AuthFilterWithCustomSecurityContext implements ContainerRequestFilter {
@Context
UriInfo uriInfo;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String authHeaderVal = requestContext.getHeaderString("Auth-Token");
String subject = validateToken(authHeaderVal); //execute custom authentication
if (subject!=null) {
final SecurityContext securityContext = requestContext.getSecurityContext();
requestContext.setSecurityContext(new SecurityContext() {
@Override
public Principal getUserPrincipal() {
return new Principal() {
@Override
public String getName() {
return subject;
}
};
}
@Override
public boolean isUserInRole(String role) {
List<Role> roles = findUserRoles(subject);
return roles.contains(role);
}
@Override
public boolean isSecure() {
return uriInfo.getAbsolutePath().toString().startsWith("https");
}
@Override
public String getAuthenticationScheme() {
return "Token-Based-Auth-Scheme";
}
});
}
}
}
我可以让它像这样工作:
申请class:
...
application.setRoles(getRoles(application));
...
public static List<Role> getRoles(JaxRsApplication application) {
List<Role> roles = new ArrayList<>();
for (AuthorizationRoleEnum authorizationRole : AuthorizationRoleEnum.values()) {
roles.add(new Role(application, authorizationRole.toString()));
}
return roles;
}
...
授权枚举:
public enum AuthorizationRoleEnum {
USER("user"),
ADMIN("admin");
private final String value;
AuthorizationRoleEnum(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
根据我的资源 classes:
...
@Context
SecurityContext securityContext;
...
allowOnlyAdmin(securityContext);
...
public void allowOnlyAdmin(SecurityContext securityContext) {
if (securityContext.getAuthenticationScheme() != null
&& !securityContext.isUserInRole(AuthorizationRoleEnum.ADMIN.toString())) {
throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN)
.entity("User does not have required " + AuthorizationRoleEnum.ADMIN + " role!").build());
}
}
...