这个问题是这里的后续问题。
在登录时,我的应用程序需要使用request.login()向容器咨询身份验证,然后设置一个"User"bean,其中包含用户名、密码、角色和一个特定于位置的字段。在对容器(WAS 8)成功授权后,需要检查用户的角色,以确定应该将用户重定向到的合适的欢迎页面。我的容器实现了一个联合存储库,它基本上将3个LDAP分支、一个数据库和一个平面文件集中在一起。有很多角色(现在有5个,以后可能会更多)。
我有两个bean:一个RequestScoped Credentials bean和一个名为Login的SessionScoped bean。Login包含一个Login()方法。我在登录方法方面有一个问题。
我的问题是每当我使用:
Principal userPrincipal = request.getUserPrincipal();
request.getUserPrincipal();
if (userPrincipal != null) {
request.logout();
}
request.login(credentials.getUsername(), credentials.getPassword());
String name = userPrincipal.getName();
:
Donor donor = loginService.getDonor(credentials.getUsername());
currentUser = new Users();
currentUser.setLocation(donor.getCenter().getCity());
currentUser.setRole("DONOR");
currentUser.setUserId(credentials.getUsername());
currentUser.setFirstName(donor.getFirstName());
currentUser.setLastName(donor.getLastName());
currentUser.setUsername(credentials.getUsername());
currentUser.setName(credentials.getUsername());
return "users?faces-redirect=true";
my currentUser User bean没有存储在会话中。
我已经删除了第一个代码块,并注意到我的User bean的信息随后存储在会话中,并且可以在后续的用户页面上查看。我已经逐行重新引入了第一块代码,并注意到:
if (userPrincipal != null) {
request.logout();
}
导致问题。
我应该如何存储实现编程安全性和JSF2.0/CDI的User bean ?我花了几个星期的时间。我可以想象实现一些更精细的东西,比如一个过滤器,捕捉重定向,获取用户主体,调用db或ldap获取额外的属性,然后重定向到适当的页面……但我想把事情简单化。一定有一个简单的方法。
我最初尝试使用j_security_check登录并在web.xml中指定FORM。现在,在使用JSF 2.0表单和登录方法时,我注意到form被忽略了,而BASIC取而代之。System.out.println("getAuthType ?…"+ request.getAuthType ());在login方法中返回"BASIC"。这会导致令人讨厌的缓存,这就是为什么请求。需要注销。否则,请求。登录失败
我昨晚偶然发现了这个,里面有一个到这里的链接。因此,可能有一种方法可以获取userprincipal、设置User bean并重定向到适当的欢迎页面。我不知道第二个链接有多过时。j_security_check似乎也不能与基于角色确定应该将用户重定向到哪个页面的编程方法一起使用。
至于我是否应该使用j_security_check或编程安全/JSF/CDI,我只需要找出一些简单的东西,并允许我在会话中存储登录bean或独立的User bean。
下面是我的登录表单:
<h:form id="loginForm">
<fieldset>
<div class="form-row">
<h:outputLabel for="username" value="User ID"/>
<h:inputText id="username" value="#{credentials.username}"
required="true" size="20" />
</div>
<div class="form-row">
<h:outputLabel for="password" value="Password"/>
<h:inputSecret id="password" type="password" value="#
{credentials.password}" required="true" />
</div>
<div class="form-row">
<h:commandButton styleClass="btn btn-warning" value="Sign In"
type="submit" action="#{login.login}" />
<a href="#" id="forgot-password">Forgot you password?</a>
</div>
</fieldset>
</h:form>
这是我的登录bean(代码已被剥离并编辑,仅显示相关部分):
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.security.auth.Subject;
import javax.security.auth.login.CredentialExpiredException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
@SessionScoped
@Named
public class Login implements Serializable {
private static final long serialVersionUID = 7965455427888195913L;
@Inject
private Credentials credentials;
@PersistenceContext
private EntityManager userDatabase;
@Inject
LoginService loginService;
private Users currentUser;
private Service service;
private String uniqueSecurityName;
private String l;
@SuppressWarnings("unchecked")
public String login() {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
System.out.println("The login method has been called.");
try {
Principal userPrincipal = request.getUserPrincipal();
request.getUserPrincipal();
if (userPrincipal != null) {
request.logout();
}
request.login(credentials.getUsername(), credentials.getPassword());
String name = userPrincipal.getName();
System.out.println("getRemoteUser?.." + request.getRemoteUser());
System.out.println("getUserPrincipal?.." + request.getUserPrincipal());
System.out.println("getAuthType?.." + request.getAuthType());
Donor donor = loginService.getDonor(credentials.getUsername());
currentUser = new Users();
currentUser.setLocation(donor.getCenter().getCity());
currentUser.setRole("DONOR");
currentUser.setUserId(credentials.getUsername());
currentUser.setFirstName(donor.getFirstName());
currentUser.setLastName(donor.getLastName());
currentUser.setUsername(credentials.getUsername());
currentUser.setName(credentials.getUsername());
return "users?faces-redirect=true";
} catch (Exception e) {}
return null;
}
public void logout() {
currentUser = null;
}
public boolean isLoggedIn() {
return currentUser != null;
}
@Produces
@LoggedIn
public Users getCurrentUser() {
return currentUser;
}
}
这是我的凭据bean:
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Default;
import javax.inject.Named;
@RequestScoped
@Named
@Default
public class Credentials implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6976596855571123825L;
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
下面是后续的users.xhtml页面(仅用于验证会话信息的测试目的):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Login</title>
<link href="style/main.css" rel="stylesheet" type="text/css"/>
<ui:insert name="head"/>
</head>
<body>
<div id="container">
<div id="header">
</div>
<div id="sidebar">
</div>
<div id="content">
<h1>Current User</h1>
<h:dataTable value="#{login.currentUser}" var="u">
<h:column>
<f:facet name="header">
Username
</f:facet>
<h:outputText value="#{u.username}" />
</h:column>
<h:column>
<f:facet name="header">
Name
</f:facet>
<h:outputText value="#{u.name}" />
</h:column>
<h:column>
<f:facet name="header">
Password
</f:facet>
<h:outputText value="#{u.password}" />
</h:column>
</h:dataTable>
</div>
<br style="clear:both"/>
</div>
</body>
</html>
这是我的用户bean:
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
@Entity
public class Users {
@Id
private String username;
private String name;
private String password;
@Transient
private String role;
@Transient
private String location;
@Transient
private String userId;
@Transient
private String firstName;
@Transient
private String lastName;
public Users() {
}
public String getUsername() {
return username;
}
public void setName(String name) {
this.name = name;
}
public void setUsername(String username) {
this.username = username;
}
public String getName() {
return name;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "User (username = " + username + ", name = " + name + ")";
}
}
你的问题如你所料,
if (userPrincipal != null) {
request.logout();
}
您正在用上面的行重新创建会话。在会话作用域bean中销毁会话并不是一个好主意。这导致会话bean被CDI清理。
当您在操作方法中清理会话bean时,您需要存储用户名,密码。
@ApplicationScoped
class LoginService{
public boolean login(String username,String password) {
String username = credentials.getUsername();
String password = credentials.getPassword();
Principal userPrincipal = request.getUserPrincipal();
request.getUserPrincipal();
if (userPrincipal != null) {
request.logout();
}
boolean loggedIn = request.login(username,password);
if(loggedIn){
users = new Users();
users.setUsername(username);
session.setAttribute("Users",users);
}
return loggedIn;
}
}
在凭据中保留登录的操作方法
@RequestScoped
class Credential {
@Inject LoginService loginService;
String username;
String password;
login(ActionEvent action){
if(loginService.login(username,password))
//redirect to users
else
//show error
}
}
创建注释从CDI获取登录用户
@Retention(RetentionPolicy.RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface SpringBean {
String value() default "";
}
使用BeanLocator类生成一些对象,您可以将此方法添加到LoginService,但最好将其单独保存
public class BeanLocator {
@Produces @LoggedInUser
public Object getSessionAttribute(InjectionPoint ip){
String beanName = ip.getAnnotated().
getAnnotation(SessionAttribute.class).value();
if(beanName==null || beanName.equals(""))
beanName = getDefaultBeanName(ip.getMember().
getDeclaringClass().getName());
return FacesContext.getCurrentInstance().getExternalContext().
getSessionMap().get(beanName);
}
}
在其他服务中使用,如
class MyOtherBean{
@Inject @@LoggedInUser Users;
}