servlet 以编程方式设置身份验证

servlet programmatically set authentication

在 JAVA EE 7 网络应用程序 (WAR) 中,需要 "manually" 将用户设置为经过身份验证的 (及其角色).

基本上我有一个令牌(JWT)和一组角色(调用Keycloak授权客户端后获得Java API)。

获得令牌后,我想将用户设置为经过身份验证(创建安全上下文),因此对安全 URL 的任何调用都不会 return 403 HTTP 错误。

在 web.xml 中定义了不同 URL 映射的角色和安全限制。

已查看 HttpServletRequest.authenticate 方法但尚未定义(不需要)登录配置机制。

(未使用 Spring 或其他框架)。

我猜这是不可能的,应该使用 servlet 过滤器来验证安全性(不是 web.xml 中的安全约束)

谢谢

您需要定义一个登录配置。对于 servlet 容器来说是必需的。 放这样的东西:

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>default</realm-name>
</login-config>

在您的 web.xml 和 HttpServletRequest.authenticate 中应该可以。

并且您应该删除此 servlet 的安全限制 因为您管理应用程序中的安全性(如果尚未完成的话)。

亲切的问候,

拉尔夫

我最初的解决方案是创建一个 servlet 过滤器,如果 JWT 令牌(来自授权 header)没有所需的角色,则 returns 未授权。

更好的方法是创建一个唯一的过滤器,为每个需要授权的请求创建安全上下文。有了这个,我可以使用 @RolesAllowed 注释。

要使 RolesAllowed 注释起作用(否则允许所有请求),重要的是添加 web.xml:

<context-param>
  <param-name>resteasy.role.based.security</param-name>
  <param-value>true</param-value>
</context-param>

我不能在 web.xml 中定义任何 auth-constraints ,否则应用程序 returns 403 Forbidden before the filter gets called.

安全过滤器:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class SecurityFilter implements ContainerRequestFilter {

    @Context private HttpServletRequest httpRequest;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

        SecurityContext originalContext = requestContext.getSecurityContext();

        // 1. Get token from the request header: "Authorization: Bearer ..."
        String token = httpRequest.getHeader("Authorization").substring(7);

        // 2. Parse the token to an AccessToken
        // calls a utility class which uses org.keycloak.TokenVerifier to get the access token
        AccessToken accessToken = KeyCloakUtils.getAccessToken(token);

        // 3.- Obtain username and roles
        String username = accessToken.getPreferredUsername(); 
        Set<String> roles = accessToken.getRealmAccess().getRoles();

        SecurityContext sc = new SecurityContext() {
            @Override
            public Principal getUserPrincipal() {
                return new User(username);
            }

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

            @Override
            public boolean isSecure() {
                return originalContext.isSecure();
            }

            @Override
            public String getAuthenticationScheme() {
                return "Your Scheme";
            } 
        };
        requestContext.setSecurityContext(sc);
    }
}

安全方法示例(接口):

@POST
@Consumes({ "application/json" })
@Produces({ "application/json" })
@RolesAllowed({"ADMIN_USER"})
public Response createUser(User user);