用于登录的身份验证过滤器和 servlet

Posted

技术标签:

【中文标题】用于登录的身份验证过滤器和 servlet【英文标题】:Authentication filter and servlet for login 【发布时间】:2012-10-27 18:40:31 【问题描述】:

我有一个用于登录的过滤器。它对“用户名”和“密码”字段执行文本检查。当且仅当文本检查正确完成时,请求才会发送到 Servlet。后者执行必须与数据库交互的控制。这个链条正确吗?

【问题讨论】:

【参考方案1】:

前言:我猜您使用的是本地登录而不是容器管理登录。各种方式见How to handle authentication/authorization with users in a database?


过滤器(拦截器)不应检查用户名/密码组合的有效性。这是 servlet(控制器)的职责。

过滤器应该只检查用户是否登录(通常只检查会话属性的存在),然后继续请求或通过重定向回登录页面来阻止它。

@WebFilter("/*")
public class LoginFilter implements Filter 

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

        boolean loggedIn = session != null && session.getAttribute("user") != null;
        boolean loginRequest = request.getRequestURI().equals(loginURI);

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

    // ...

servlet 应该收集提交的数据,在数据库中找到关联的User,如果找到则将其存储为会话属性,然后重定向到主页,否则重新显示验证错误的表单。

@WebServlet("/login")
public class LoginServlet extends HttpServlet 

    @EJB
    private UserService userService;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
        request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
    

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        Map<String, String> messages = new HashMap<String, String>();

        if (username == null || username.isEmpty()) 
            messages.put("username", "Please enter username");
        

        if (password == null || password.isEmpty()) 
            messages.put("password", "Please enter password");
        

        if (messages.isEmpty()) 
            User user = userService.find(username, password);

            if (user != null) 
                request.getSession().setAttribute("user", user);
                response.sendRedirect(request.getContextPath() + "/home");
                return;
             else 
                messages.put("login", "Unknown login, please try again");
              
        

        request.setAttribute("messages", messages);
        request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
    


另见:

Our servlet-filters wiki page Our servlets wiki page

【讨论】:

+1。并且为了更好的用户体验,如果截获的请求是 GET,则将其缓存(或将其添加为登录页面中的隐藏字段),并在登录成功后重定向到该页面。 一个具体的例子可以在这里找到:***.com/questions/6388014/… 不客气。确保没有在登录页面本身上调用过滤器!否则它可能会陷入无限循环。您需要将受限页面放在单独的文件夹中(以便可以使用 /somefolder/* 的 URL 模式),或者如果最终用户当前未请求登录,则对请求 URL 添加额外检查页面。 您能解释一下对登录页面的额外检查,还是排除 js 或 css 页面? 我试过这个,但它一直失败,并出现以下错误code 原因:java.lang.RuntimeException:无法编译的源代码 - LoginFilter 不是抽象的,并且不会覆盖 javax 中的抽象方法 destroy()。 servlet.Filter 在 LoginFilter.(LoginFilter.java:15)

以上是关于用于登录的身份验证过滤器和 servlet的主要内容,如果未能解决你的问题,请参考以下文章

使用 Servlet 对浏览器和 android 应用程序进行相同的登录身份验证

覆盖 JSP servlet(过滤器“*.jsp”)以包装身份验证模型

如何通过 ldap 身份验证和授权将安全性应用于登录流程?

Spring Security:在 servlet 过滤器中访问当前经过身份验证的用户

Spring Security 中用于身份验证的通用身份验证过滤器

Java EE 身份验证和授权 [关闭]