JSF HTTP 会话登录

Posted

技术标签:

【中文标题】JSF HTTP 会话登录【英文标题】:JSF HTTP Session Login 【发布时间】:2011-04-19 23:22:29 【问题描述】:

我尝试在 Web 应用程序中创建登录表单。 在 JSP 页面中我可以使用

<%
   String name = request.getParameter( "username" );
   session.setAttribute( "theName", name );
%>

但现在我正在使用 JSF /Facelets 进行 Web 应用程序 我不知道如何在 JSF Backing bean 中为客户端创建会话并检查用户是否已登录,因此它将重定向到登录页面。 谁能帮我给我这些问题的链接教程? 之前谢谢你

现在我对映射到 web.xml 没有什么问题 类Filter的代码片段

@Override
public void init(FilterConfig filterConfig) throws ServletException 
    this.config = filterConfig;


@Override
public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException 
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    LoginController controller = (LoginController) req.getSession()
            .getAttribute("loginController");
    if (controller == null || !controller.isLoggedIn()) 
        res.sendRedirect("../admin/login.xhtml");
     else 
        chain.doFilter(request, response);
    

web.xml 中,我使用&lt;fitler&gt; 标签进行映射

<filter>
    <filter-name>userLoginFilter</filter-name>
    <filter-class>com.mcgraw.controller.UserLoginFilter</filter-class>
    <init-param>
        <param-name>loginPage</param-name>
        <param-value>/login.xhtml</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>userLoginFilter</filter-name>
    <url-pattern>/admin/*</url-pattern>
</filter-mapping>

我在 web 项目中有一个文件夹管理员,我检查用户是否没有以管理员权限登录以不访问页面(我可以进行权限检查)但是当我使用过滤器时浏览器不理解 url? ? 浏览器不理解 url 时不显示 StackTrace

Firefox 显示错误

The page isn't redirecting properly

在 IE 上它正在加载...正在加载。 ..不停

现在我更改检查 req.getPathInfo.startsWith("/login.xhtml") 是否会执行链接的条件

我有 2 个想法,但它响应 500 HTTP STATUS

 if (controller == null || !controller.isLoggedIn()) 
     res.sendRedirect("../admin/login.xhtml");
     if(req.getPathInfo().startsWith("/login.xhtml"))
     chain.doFilter(request, response);


 else 
     chain.doFilter(request, response);

================

if (controller == null || !controller.isLoggedIn()) 
    if (!req.getPathInfo().startsWith("/login.xhtml")) 
        res.sendRedirect("../admin/login.xhtml");
     else 
        chain.doFilter(request, response);
    
 else 
    chain.doFilter(request, response);

======================= 更新类 loginController

package com.mcgraw.controller;

import com.DAO.UserBean;
import com.entity.IUser;
import java.io.Serializable;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

/**
 * @author Kency
 */
@ManagedBean
@SessionScoped
public class LoginController implements Serializable 

    @EJB
    private UserBean userBean;
    private IUser user;
    private boolean admin;
    private boolean mod;
    private PasswordService md5;

    /** Creates a new instance of LoginController */
    public LoginController() 
        user = new IUser();
        md5 = new PasswordService();
    

    // getter / setter
    public boolean isMod() 
        return mod;
    

    public void setMod(boolean mod) 
        this.mod = mod;
    

    public IUser getUser() 
        return user;
    

    public void setUser(IUser user) 
        this.user = user;
    

    public boolean isAdmin() 
        return admin;
    

    public void setAdmin(boolean admin) 
        this.admin = admin;
    

    public String cplogin() 
        String md5Password = md5.md5Password(user.getPassword());
        if (userBean.userLogin(user.getUsername(), md5Password) != null) 
            if (user.getUsername() != null || md5Password != null) 
                user = userBean.userLogin(user.getUsername(), md5Password);
                if (user.getGroups().getAdmin() != null) 
                    setAdmin(user.getGroups().getAdmin());
                
                if (user.getGroups().getMods() != null) 
                    setMod(user.getGroups().getMods());
                
                if (isAdmin() == true || isMod() == true) 
                    return "home";
                 else 
                    return "login";
                
             else 
                return "login";
            
         else 
            return "login";
        
    

    public String logout() 
        user = null;
        return "login";
    

    public boolean isLoggedIn() 
        return user != null;
    

如果使用方法loggedIn 呈现JSF taglib,我有新问题,在索引页面(不在管理文件夹中)用户没有登录可以看到我呈现的示例,

【问题讨论】:

【参考方案1】:

您可以在 JSF 中通过 ExternalContext#getSessionMap() 获取/设置 HTTP 会话属性,这基本上是 HttpSession#get/setAttribute() 的包装器。

@Named
@RequestScoped
public class LoginController 

    private String username;
    private String password;

    @EJB
    private UserService userService;

    public String login() 
        User user = userService.find(username, password);
        FacesContext context = FacesContext.getCurrentInstance();

        if (user == null) 
            context.addMessage(null, new FacesMessage("Unknown login, try again"));
            username = null;
            password = null;
            return null;
         else 
            context.getExternalContext().getSessionMap().put("user", user);
            return "userhome?faces-redirect=true";
        
    

    public String logout() 
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        return "index?faces-redirect=true";
    

    // ...

在 Facelets 页面中,只需将 usernamepassword 输入字段绑定到此 bean 并相应地调用 login() 操作。

<h:form>
    <h:inputText value="#loginController.username" />
    <h:inputSecret value="#loginController.password" />
    <h:commandButton value="login" action="#loginController.login" />
</h:form>

会话属性可以在 EL 中直接访问。名称为user 的会话属性在EL 中可用作#user。在测试用户是否登录某个rendered 属性时,只需检查它是否为empty

<h:panelGroup rendered="#not empty user">
    <p>Welcome, #user.fullName</p>
    <h:form>
        <h:commandButton value="logout" action="#loginController.logout" />
    </h:form>
</h:panelGroup>

注销操作基本上只是破坏会话。


关于检查用户是否登录的传入请求,只需创建一个Filter,它在doFilter()方法中大致执行以下操作:

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException     
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    HttpSession session = request.getSession(false);
    String loginURI = request.getContextPath() + "/login.xhtml";

    boolean loggedIn = session != null && session.getAttribute("user") != null;
    boolean loginRequest = request.getRequestURI().equals(loginURI);
    boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER);

    if (loggedIn || loginRequest || resourceRequest) 
        chain.doFilter(request, response);
     else 
        response.sendRedirect(loginURI);
    

将其映射到覆盖受限页面的url-pattern,例如/secured/*/app/*

另见:

How to handle authentication/authorization with users in a database? Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same

【讨论】:

嗨 BalusC 一切都好,但我对映射到 web.xml 页面没有什么问题,你可以看到上面我正在编辑的问题,我在 web 项目中有文件夹 admin 并重定向到 ../admin/login .xhtml 它不起作用浏览器不理解它 如果登录页面被放置在/admin,那么同样的过滤器将被再次调用并且它将进入一个无限重定向循环,因为用户没有登录。要么放置登录页面在/admin 之外,或者添加一个条件来检查req.getPathInfo().startsWith("/login.xhtml") 是否存在,然后继续循环,不要重定向。 我再次使用您建议的解决方案编辑了我的问题,但我在 glassfish 服务器中检索到错误 500 HTTP 状态,它抛出空指针异常 好的,您的过滤器中的路径信息显然是null。请改用req.getRequestURI().endsWith("/login.xhtml") @Li3ro:这只是模范。自己写吧。这是一个简单的@Stateless EJB,它执行持久性工作(例如通过 JPA 或普通的旧 JDBC)。【参考方案2】:

在收到请求时在您的支持 bean 中尝试此操作(如在操作方法中):

HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
HttpSession session = request.getSession();

然后您可以像使用 JSP 一样使用请求和会话对象,设置属性等等。

您可能还想看看我的related question about checking the client session in a servlet Filter。您可以编写一个类似的过滤器来检查用户在他们的 HttpSession 中的登录,然后在需要时重定向(或像我最终做的那样 RequestDispatch)到您的登录页面。

【讨论】:

HttpSession 有方法 setAttribute() 在 jSP 中相同的会话,但我如何维护和检查客户端中的会话? @Kency 我不明白你之前在做什么。您可以编辑您的问题并提供一些旧代码吗?当您说“检查客户端中的会话”时,您实际上是指您正在使用 javascript 在客户端检查某些内容吗? 我找到了 phaselistenter 来检查 JSF 的用户登录。我的问题是当用户通过网络浏览器访问网页时 jsf 将检查用户登录或不检查这意味着在 jsp 中我写了 1 页 session.getAttribute("thename") 并将其包含在我想检查用户登录或不登录的标题页中.但是使用 phaselistener 会检查它,但现在我还不了解 phaselistener 的工作。你有 JSF 登录会话的教程链接,如果有的话?如果你给我教程链接谢谢

以上是关于JSF HTTP 会话登录的主要内容,如果未能解决你的问题,请参考以下文章

JSF 登录过滤器,会话为空

如何在 JSF 中使用会话实现多用户登录

新的 Spring Security 登录会话启动时是不是启动了新的 JSF 会话?

JSF 2 + Spring 3 + Shiro - 会话超时不重定向到登录页面

检查会话是不是存在 JSF

Spring 安全性和 JSF:在登录时调用支持 bean 的方法?