认证

2012-01-31 79 views
4

后以编程方式添加角色,我有以下JSF 2.1的登录表单,在Glassfish的3.1认证

<h:form id="loginForm"> 
     <h:panelGrid columns="2" cellspacing="5"> 
      <h:outputText value="Username" /> 
      <h:inputText value="#{loginHandler.username}" /> 
      <h:outputText value="Password:" /> 
      <h:inputText value="#{loginHandler.password}" /> 
      <h:outputLabel value="" /> 
      <h:commandButton value="Login" action="#{loginHandler.login}" /> 
     </h:panelGrid> 
    </h:form> 

运行而下面的支持bean。

public String login() throws IOException, LoginException { 

    log.debug("Trying to login with username " + username); 

    HttpSession session = getRequest().getSession(true); 

    try { 
     getRequest().login(username, password); 

     // if OK, add Roles 
        ???????? 
        ................... 

    } catch (ServletException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 


    log.debug("USER principal === " + getRequest().getUserPrincipal()); 

    return "home"; 
} 

问题是,如何在成功登录后以编程方式向UserPrincipal添加角色?

更新1:我试图通过使用下面的代码,但主题== null来获取主题。

Subject thisSubject = Subject.getSubject(AccessController 
       .getContext()); 

感谢, 科恩

+0

是否要硬编码每个用户的角色?如果你使用容器认证,角色应该来自认证领域。 – oers 2012-02-01 09:18:55

+0

嗨,我需要查询另一个LDAP树的某些角色,并将这些角色分配给用户。角色在web.xml中定义。因此,身份验证是容器管理的,但分配角色不是。 – 2012-02-01 09:31:13

回答

2

OK,我已经找到了一个解决办法,这是我的观点不是100%正确的,但建议,欢迎:)

public void login() throws IOException, LoginException { 

    log.debug("Trying to login with username " + username); 

    try { 
     getRequest().login(username, password); 

     HttpSession session = getRequest().getSession(true); 
     Subject subject = (Subject) session 
       .getAttribute("javax.security.auth.subject"); 

     if (subject == null) { 

      log.debug("Subject is null, creating new one"); 

      subject = new Subject(); 
      subject.getPrincipals().add(new PlainRolePrincipal("USER")); 
      subject.getPrincipals().add(new PlainRolePrincipal("ADMIN")); 

     } 

     log.debug("HAS USER " + getRequest().isUserInRole("USER")); 
     log.debug("HAS ADMIN " + getRequest().isUserInRole("ADMIN")); 
     log.debug("HAS REPORT " + getRequest().isUserInRole("REPORT")); 

     session.setAttribute("javax.security.auth.subject", subject); 

     log.debug("USER principal === " + getRequest().getUserPrincipal()); 

     FacesContext.getCurrentInstance().getExternalContext() 
       .redirect("pages/home.jsf"); 

    } catch (ServletException e) { 

     FacesContext.getCurrentInstance().addMessage("Login", 
       new FacesMessage("Invalid Username/Password combination")); 

     e.printStackTrace(); 
    } 

} 

而且我使用以下信息bean来检索主题并检查主体。

@ManagedBean(name = "userInfo") 
@SessionScoped 
public class UserInformation { 

/** 
* Fetches current logged in username. 
* 
* @return 
*/ 
public String getUsername() { 

    return FacesContext.getCurrentInstance().getExternalContext() 
      .getRemoteUser(); 

} 



public boolean isUserInRole(String roleName) { 
    Subject subject = (Subject) getRequest().getSession().getAttribute(
      "javax.security.auth.subject"); 

    for (Principal p : subject.getPrincipals()) { 
     if (p.getName().equals(roleName)) { 
      return true; 
     } 
    } 

    return false; 
} 


public static HttpServletRequest getRequest() { 
    Object request = FacesContext.getCurrentInstance().getExternalContext() 
      .getRequest(); 
    return request instanceof HttpServletRequest ? (HttpServletRequest) request 
      : null; 
} 

}

所以我的解决方法的isUserInRole机制,因为身份验证时,该角色被设定的真正的isUserInRole方法返回只在用户真实。

从JSF页面我现在可以做

<p:menuitem value="Create" action="#{menuController.XXXXXCreate}" 
       ajax="false" helpText="Create new XXXXX" 
       disabled="#{!userInfo.isUserInRole('ADMIN')}" /> 

希望这有助于其他用户,任何改进建议,欢迎!

+0

你从哪里找到属性:“javax.security.auth.subject”?这是一个发布的属性,不太可能改变。我很好奇也使用它。 你是什么意思:“所以我解决isUserInRole机制,”? – BillR 2012-09-10 02:22:21

5

我想出了以下解决方案登录后以编程方式添加角色,其工作至少在GlassFish 3.1.2建立23

import com.sun.enterprise.security.SecurityContext; 
import com.sun.enterprise.security.web.integration.PrincipalGroupFactory; 
import java.security.Principal; 
import java.util.Set; 
import javax.security.auth.Subject; 
import org.glassfish.security.common.Group; 

public class GlassFishUtils { 
    public static void addGroupToCurrentUser(String groupName, String realmName) { 
     Subject subject = SecurityContext.getCurrent().getSubject(); 
     Set<Principal> principals = subject.getPrincipals(); 
     Group group = PrincipalGroupFactory.getGroupInstance(groupName, realmName); 
     if (!principals.contains(group)) 
      principals.add(group); 
    } 
} 

您需要添加从GlassFish的security.jarcommon-util.jar到项目库。

并且不要忘记在web.xml中为您想添加的角色创建一个<security-role>部分。

请注意,我使用的功能似乎不是已发布的稳定API的一部分,因此无法保证在未来的GlassFish版本中这些功能仍能正常工作。

我收到了关于如何从GlassFish的sun.appserv.security.AppservPasswordLoginModule.commit()的源代码添加角色的信息。 如果将来的GlassFish发布会破坏我的代码,那么此函数将是一个很好的开始以了解如何修复它的地方。

+0

“真名”是指什么?成为主体的登录名?就像在JSF中一样,你做了一个:FacesContext.getCurrentInstance()。getExternalContext()。getUserPrincipal();是吗?没有? – BillR 2012-09-10 02:28:50

+0

这不是“真正的”,而是“领域”,就像在JAAS身份验证领域一样。有关领域的更多信息,请参阅http://docs.oracle.com/cd/E19798-01/821-1841/bnbxj/index.html。 realmName参数是标识领域的字符串,如在GlassFish中配置的。 – SvdB 2012-09-11 10:55:03

+0

< BIG grin&gt。那么我需要新的眼镜。大声笑。是的,我知道realM的名字。我已经定制了JDBC领域来做更多我需要做的事情,并绕过他们期望桌子被设置的愚蠢的方式(以及允许处理盐渍密码等)。:)感谢您的答案。至少这看起来值得一试。谢谢。 – BillR 2012-09-11 16:23:09