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());
  }
}
...