为用户分配角色

时间:2018-08-10 14:20:52

标签: java-ee glassfish payara

我没有让所有用户有权执行所有操作,而是尝试将角色(管理员,用户)添加到正在运行的Java EE项目中。

我自己开始,改变表,编写自己的机制,并计划用@WebFilter进行编程控制。

很快,我发现Java EE为此具有某种内置机制。

我要使用的是此角色过滤器注释:

@RolesAllowed("ADMIN")
public void adminAllowedFunction(){
    //code
}

但是如何将角色分配给实际的用户/会话。另外,用户在这种情况下是什么意思?需要记录在表中以满足某些约定,或者我正在做的所有工作都是将角色分配给实际会话?

我还阅读了一些有关将角色映射到glassfish / payara用户(领域)的知识。那是正确的方法吗?我没有发现明确的解释,仅关于<security-role-mapping>中的glassfish-web.xml,但是如何在Java代码中抓住它呢?

我真的对Java EE机制感到困惑。我怀疑我不明白它的意图。

我已经尝试过拒绝所有该功能的角色:

@DenyAll
public String getUserName(){
    return (String) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("loggedUser");

}

但是当它被拒绝时我无法获得条件。

我将感谢所有有用的信息。另外,不必担心一堆代码示例。

1 个答案:

答案 0 :(得分:1)

通常,您需要使用Java EE身份验证机制。此类身份验证机制在请求开始时被调用,并将与调用方进行交互以获得凭证。如果这些凭据经过正确验证,则可以在当前请求中设置呼叫者姓名或呼叫者主体以及几个角色。

调用方名称和角色的来源对于Java EE而言并不重要。您的代码可以即时创建它们,从内存存储中获取它们,从数据库中查询它们,从LDAP服务器中获取它们,等等。

通常(但不是必须),身份验证机制将验证凭证的任务委托给与上述某种商店进行交互的专用组件。这就是所谓的“身份存储”(关于同一件事,还有大约20个其他术语,但是Java EE对此进行了标准化)。

以下给出了身份存储的示例:

@ApplicationScoped
public class TestIdentityStore implements IdentityStore {

    public CredentialValidationResult validate(UsernamePasswordCredential usernamePasswordCredential) {

        if (usernamePasswordCredential.compareTo("reza", "secret1")) {
            return new CredentialValidationResult("reza", new HashSet<>(asList("foo", "bar")));
        }

        return INVALID_RESULT;
    }

}

自定义身份验证机制如下:

@ApplicationScoped
public class TestAuthenticationMechanism implements HttpAuthenticationMechanism {

    @Inject
    private IdentityStoreHandler identityStoreHandler;

    @Override
    public AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationException {

        if (notNull(request.getParameter("name"), request.getParameter("password"))) {

            // Get the (caller) name and password from the request
            // NOTE: This is for the smallest possible example only. In practice
            // putting the password in a request query parameter is highly
            // insecure
            String name = request.getParameter("name");
            Password password = new Password(request.getParameter("password"));

            // Delegate the {credentials in -> identity data out} function to
            // the Identity Store
            CredentialValidationResult result = identityStoreHandler.validate(
                new UsernamePasswordCredential(name, password));

            if (result.getStatus() == VALID) {
                // Communicate the details of the authenticated user to the
                // container. In many cases the underlying handler will just store the details 
                // and the container will actually handle the login after we return from 
                // this method.
                return httpMessageContext.notifyContainerAboutLogin(
                    result.getCallerPrincipal(), result.getCallerGroups());
            } 

            return httpMessageContext.responseUnauthorized();
        } 

        return httpMessageContext.doNothing();
    }

}

请注意,以上内容仅用于 DEMO 目的,而不是现实的甚至是安全的身份验证机制!

另请参阅:https://github.com/eclipse-ee4j/soteria/tree/master/test/app-mem/src/main/java/org/glassfish/soteria/test

通常,您不会编写自己的身份验证机制甚至身份存储,但是会重用Java EE提供的身份验证机制。例如:

@CustomFormAuthenticationMechanismDefinition(
    loginToContinue = @LoginToContinue(
        loginPage="/login.jsf",
        errorPage=""
    )
)
@ApplicationScoped
public class ApplicationInit {
}

通过查询或注入当前呼叫者/用户主体的能力而存在用户的概念。例如使用:

@Inject
private Principal principal;

或使用Servlet API:

HttpServletRequest#getUserPrincipal();

这是@RolesAllowed和类似构造也要检查的同一“用户”(经过身份验证的身份)。

组到角色的映射始终是可选的,并且默认情况下,组与角色相同。有些服务器甚至根本不支持组到角色的映射。