Cookie实现免密登陆

Cookie+Session实现免密登陆

先大体说一下流程,看图:
在这里插入图片描述css

拦截器执行的逻辑大体以下:

  • 不受限资源:直接放行请求,请求原来访问哪就让他访问哪
  • 受限资源:
    • 首先判断当前会话中是否存在登陆用户,也就是用户已经登陆了,直接放行
    • 若是session中没有存登陆用户,那就获取请求头中获取cookie,看下cookie中是否有登陆信息,若是有则说明用户但愿免密登陆,取出数据而且存入session,而后放行资源
    • 以上两种状况都不符合说明用户没有登陆,其次又没有作免密登陆,只能拦截下来重定向到登陆页面了

项目工程:
在这里插入图片描述
pom.xml:html

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-api</artifactId>
        <version>8.5.41</version>
    </dependency>

    <!--对象转json-->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.8</version>
    </dependency>
</dependencies>

登陆请求处理

  • 校验用户名密码是否正确,将用户信息存入session中,若是勾选了"记住我"那么须要给前端响应cookie
package com.horizon.temp.servlet;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.horizon.temp.entity.User;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

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

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //模拟数据库的用户
        User dbUser=new User("root","admin");
        /** * 接收前端参数 */
        String username = request.getParameter("username");
        String password= request.getParameter("password");
        String remember = request.getParameter("remember");


        System.out.println(remember);

        if(username.equals(dbUser.getUsername()) && password.equals(dbUser.getPassword())){
            // 用户名密码正确
            HttpSession session = request.getSession();

            //存入session
            session.setAttribute("loginUser",dbUser);

            //若是勾选了提交过来的应该是1(若是没有勾选则不会提交,remember的值为null)
            if("1".equals(remember)){

                //说明用户勾选了"记住我"

                ObjectMapper om=new ObjectMapper();

                //转换为json:{"username":"root","password":"admin"}
                //这里你也能够加密,我就不加密了
                String userJson = om.writeValueAsString(dbUser);

                Cookie cookie=new Cookie("loginUser",userJson);
                //设置cookie携带路径为整个项目都携带
                cookie.setPath(request.getContextPath());

                //设置cookie有效期(7天),cookie的过时时间是基于秒设置的(session也是)
                cookie.setMaxAge(60*60*24*7);

                response.addCookie(cookie);

            }

            response.sendRedirect(request.getContextPath()+"/home.jsp");
            return;
        }
        request.setAttribute("error","用户名或密码错误");
        request.getRequestDispatcher("/login.jsp").forward(request,response);

    }
}

登陆页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>


<form action="${pageContext.request.contextPath}/login">

    用户名:<input type="text" name="username">
    <hr>
    密码:<input type="password" name="password">
    <hr>
    <label for="remember">记住我</label>
    <input type="checkbox" name="remember" id="remember" value="1">
    <hr>
    <p style="color:red">${error}</p>
    <input type="submit">
</form>
</body>
</html>

核心拦截器

  • 主要是针对受限资源以及不受限资源分别进行处理,详细逻辑请看文章上面的流程图以及解释
package com.horizon.temp.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.horizon.temp.entity.User;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")           //拦截全部的请求
public class LoginFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        //转换为Http(功能方法更丰富)
        HttpServletRequest request=(HttpServletRequest)servletRequest;
        HttpServletResponse response=(HttpServletResponse)servletResponse;

        /** * 浏览器请求:http://localhost:8080/Temp/home.jsp * request.getRequestURI():/Temp/home.jsp * request.getRequestURL():http://localhost:8080/Temp/home.jsp */
        String uri = request.getRequestURI();

        //只要/Temp/home.jsp 请求"/"后面的字符串(home.jsp)
        uri=uri.substring(uri.lastIndexOf("/")+1);

        /** * 放行 index.jsp、login.jsp、logout请求、login请求等 * * 不受限内容 */
        if(
                uri.equals("index.jsp")
                || uri.equals("login.jsp")
                || uri.equals("logout")
                || uri.equals("login")
        ){

            //放行资源
            filterChain.doFilter(request, response);

            //记住这里要加return,要否则请求放行了代码仍是会往下执行
            return;
        }


        /** * 受限内容 */
        HttpSession session = request.getSession();
        if(session.getAttribute("loginUser")!=null){


            //虽然是受限内容,可是仍然处于一次会话中,即:用户已经登陆过了
            filterChain.doFilter(request,response);

            return;
        }

        Cookie[] cookies = request.getCookies();
        Cookie loginCookie=null;
        if(cookies!=null){
            for (Cookie cookie : cookies) {
                //看下请求头中的全部cookie是否有包含"loginCookie"
                if(cookie.getName().equals("loginUser")){
                    loginCookie=cookie;
                }
            }
        }

        if(loginCookie!=null){
            //说明请求头上的cookie是有携带登陆信息的
            //准备读取cookie中的value转回user存入session
            ObjectMapper mapper=new ObjectMapper();

            User user = mapper.readValue(loginCookie.getValue(), User.class);

            session.setAttribute("loginUser",user);
            filterChain.doFilter(request,response);

            return;
        }


        //重定向到登陆页面
        response.sendRedirect(request.getContextPath()+"/login.jsp");

    }

    @Override
    public void destroy() {

    }
}

退出登陆

  • 在session中销毁登陆标识符,销毁cookie标识符,重定向到登陆页
package com.horizon.temp.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 清除当前登陆用户
        request.getSession().removeAttribute("loginUser");

        // 清除cookie
        Cookie cookie=new Cookie("loginUser","");
        cookie.setMaxAge(0);

        response.addCookie(cookie);

        response.sendRedirect(request.getContextPath()+"/login.jsp");
    }
}

测试

勾选记住我

  • 发现响应头中有响应"loginUser"
    在这里插入图片描述
  • 查看浏览器中的cookie信息
    在这里插入图片描述
    其余状况你们自行断点测试,我就带你们测试到这里了

总结

总体来讲仍是比较简单的,流程的话你们能够看文章最上面写的步骤前端

项目中须要注意的一个点:java

  • 登陆的时候Cookie的携带路径设置是cookie.setPath(request.getContextPath());或者设置为cookie.setPath("/");,表明整个项目下的全部路径都携带此Cookie,可是确定不少人有疑问,原来使用Cookie历来没有设置过这个东西啊,也同样能成功啊?若是没有设置默认的访问路径为当前的路径的上一级路径,就会有问题了

若是没听懂的话能够看个人另一篇文章:Cookie携带路径详解web