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

时间:2019-08-23 09:54:43

标签: java java-ee java-8 keycloak servlet-3.0

在JAVA EE 7 Web应用程序(WAR)中,需要“手动”将用户设置为已认证(及其角色)。

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

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

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

已经研究了HttpServletRequest.authenticate方法,但尚未定义(无需)login-config机制。

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

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

谢谢

2 个答案:

答案 0 :(得分:1)

您需要定义一个登录配置。 servlet容器是必需的。 像这样:

{
              "policyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                  {
                    "Action": "execute-api:Invoke",
                    "Resource": [
                      "arn:aws:execute-api:us-east-1:1234567:myapiId/staging/POST/*"
                    ],
                    "Effect": "Allow"
                  }
                ]
              },
              "principalId": "Foo"
            }
您的web.xml和HttpServletRequest.authenticate中的

应该可以工作。

并且您应该删除此Servlet的安全性约束 因为您尚未管理应用程序中的安全性。

亲切的问候,

拉尔夫

答案 1 :(得分:0)

我最初的解决方案是创建一个servlet过滤器,如果JWT令牌(出现在Authorization标头中)没有所需的角色,则返回UNAUTHORIZED。

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

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

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

我无法在web.xml中定义任何身份验证约束,否则应用程序甚至会在调用过滤器之前返回403 Forbidden。

安全过滤器:

@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);