认证学习5 - Cookie、会话认证讲解、代码实现、演示


认证大全(想学习其他认证,请到此链接查看)

Cookie认证

参考文章: https://blog.csdn.net/qq_35642036/article/details/82788588

注意: 登录成功时的响应报文头会多了个Set-Cookie字段,目的是下次新的请求都会携带这些信息在请求头cookie里面

Cookie信息存储令牌 - 用户信息存储在用户本机中

小知识点: 利用请求头中cookie中的用户身份标识来进行认证校验

讲解(Cookie认证-客户端)

官方文章(Cookie): https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies

官方文章(Set-Cookie): https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie

内置-键key
内置-键key
内置-键key
内置-键key
内置-键key
内置-键key
Cookie信息
Name和Value:其他信息键值对
Domain:Cookie支持的域名(会包括子域名),格式:.开始,如.test.com,则a.test.com、test.com都支持
Path:Cookie支持的路径(会包括子路径),格式/开始,如/test,则支持/test/user或者/test
Expires:Cookie的有效期 == 不设置则是会话cookie,关闭浏览器就会消息
Max-age:Cookie的有效期 == 不设置则是会话cookie,关闭浏览器就会消息
HttpOnly:true则不允许通过JavaScript脚本获取的Cookie信息,但是发送时会将cookie发送过去给服务 == 默认false
Secure:true仅HTTPS请求头才会携带Cookie == 默认false
实现(Cookie认证-客户端)
代码(Cookie认证-客户端)

文件结构
在这里插入图片描述

application.yml

server:
  port: 8080

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
    cache-enabled: true
  mapper-locations: classpath:mapper/*Mapper.xml
  global-config:
    db-config:
      id-type: assign_uuid
      logic-delete-value: 1
      logic-not-delete-value: 0
      logic-delete-field: is_del
      where-strategy: not_empty 
      update-strategy: not_empty
      insertStrategy: not_empty
spring:
  datasource:
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    username: root
    password: root
    url: jdbc:p6spy:mysql://localhost:3306/lrc_blog?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai


  freemarker:
    suffix: .html


CookieAuthInterceptor.java

package work.linruchang.qq.mybaitsplusjoin.config.interceptor;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.stream.Stream;

/**
 * 作用:
 *
 * @author LinRuChang
 * @version 1.0
 * @date 2022/08/04
 * @since 1.8
 **/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CookieAuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        boolean authStatusFlag = false;

        Cookie[] cookies = ObjectUtil.defaultIfNull(request.getCookies(), new Cookie[0]);
        String cookieCredentials = Stream.of(cookies)
                .filter(cookie -> StrUtil.equals(cookie.getName(), "credentials"))
                .findFirst()
                .map(Cookie::getValue)
                .orElse(null);

        String cookieUserName = Stream.of(cookies)
                .filter(cookie -> StrUtil.equals(cookie.getName(), "userName"))
                .findFirst()
                .map(Cookie::getValue)
                .orElse(null);


        if(StrUtil.isAllNotBlank(cookieCredentials,cookieUserName)) {
            //根据userName获取数据库存储的用户信息 == 这里我默认只取root用户
            Dict dbUserInfo = getUserInfo(cookieUserName);
            String dbCredentials = dbUserInfo != null ? SecureUtil.md5(StrUtil.format("{}:{}", dbUserInfo.getStr("userName"), dbUserInfo.getStr("password"))) : null;
            if(StrUtil.equals(dbCredentials,cookieCredentials)) {
                authStatusFlag = true;
            }
        }



        //认证失败 == 重定向到登录页面
        if (!authStatusFlag) {
            StringBuffer url = request.getRequestURL();
            if (request.getQueryString() != null) {
                url.append("?");
                url.append(request.getQueryString());
            }
            response.sendRedirect(StrUtil.format("/user/login?targetUrl={}?{}",request.getRequestURL().toString(),StrUtil.nullToEmpty(request.getQueryString())));
        }

        return authStatusFlag;
    }

    /**
     * 自行改成获取数据库的逻辑
     * @param userName
     * @return
     */
    public Dict getUserInfo(String userName) {
        if(StrUtil.equals(userName,"admin")) {
            return Dict.create()
                    .set("userName","admin")
                    .set("password", "admin123");

        }
        return null;
    }
}

MyConfig.java

@Configuration
public class MyConfig implements WebMvcConfigurer {

    @Autowired
    CookieAuthInterceptor cookieAuthInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(cookieAuthInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/static/**","/user/login/**","/user/logout/**");
    }
}


UserController .java

package work.linruchang.qq.mybaitsplusjoin.controller;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import lombok.SneakyThrows;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import work.linruchang.qq.mybaitsplusjoin.common.response.CommonHttpResult;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 作用:
 *
 * @author LinRuChang
 * @version 1.0
 * @date 2022/08/05
 * @since 1.8
 **/
@Controller
@RequestMapping("user")
public class UserController {

    /**
     * 登录页面
     * @param httpServletRequest
     * @param modelAndView
     * @return
     */
    @GetMapping("login")
    public ModelAndView loginPage(HttpServletRequest httpServletRequest, ModelAndView modelAndView) {
        modelAndView.setViewName("login");
        modelAndView.addObject("targetUrl", httpServletRequest.getParameter("targetUrl"));
        return modelAndView;
    }

    /**
     * 登录
     * @param httpServletRequest
     * @param httpServletResponse
     * @param modelAndView
     */
    @PostMapping( "login")
    @SneakyThrows
    public void login(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, ModelAndView modelAndView) {
        String userName = httpServletRequest.getParameter("userName");
        String password = httpServletRequest.getParameter("password");
        String targetUrl = httpServletRequest.getParameter("targetUrl");

        if (StrUtil.equals(userName, "admin") && StrUtil.equals(password, "admin123")) {
            
            //cookie有效期为1天
            Integer secondDate = Integer.valueOf(String.valueOf(DateUnit.DAY.getMillis()/1000));

            String credentials = SecureUtil.md5(StrUtil.format("{}:{}", userName, password));
            Cookie cookie = new Cookie("credentials", credentials);
            cookie.setPath("/");
            cookie.setMaxAge(secondDate);
            httpServletResponse.addCookie(cookie);

            //用户名-用于前端JS显示用户信息
            Cookie cookie2 = new Cookie("userName", "admin");
            cookie2.setPath("/");
            cookie2.setMaxAge(secondDate);
            httpServletResponse.addCookie(cookie2);

            if (StrUtil.isNotBlank(targetUrl)) {
                httpServletResponse.sendRedirect(targetUrl);
            } else {
                httpServletResponse.setHeader("Content-Type", "application/json;charset=UTF-8");
                httpServletResponse.getWriter().print(JSONUtil.toJsonStr(CommonHttpResult.success("登录成功")));
            }
        }else {
            httpServletResponse.sendRedirect(StrUtil.format("login?targetUrl={}", targetUrl));
        }

    }

    /**
     * 退出登录 == 命令浏览器删除cookie
     *
     * @return
     */
    @GetMapping("logout")
    public String logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,ModelAndView modelAndView) {

        httpServletRequest.getCookies();

        Cookie cookie = new Cookie("credentials", null);
        cookie.setPath("/");
        cookie.setMaxAge(0);
        httpServletResponse.addCookie(cookie);

        Cookie cookie2 = new Cookie("userName", null);
        cookie2.setPath("/");
        cookie2.setMaxAge(0);
        httpServletResponse.addCookie(cookie);
        httpServletResponse.addCookie(cookie2);


        return "redirect:/user/login";
    }

}


ArticleCategoryController.java

@RestController
@RequestMapping("article-category")
public class ArticleCategoryController {

    @Autowired
    ArticleCategoryService articleCategoryService;

    @DeleteMapping("one/{id}")
    public CommonHttpResult<String> deleteById(@PathVariable("id") String id) {
        boolean deleteFlag = articleCategoryService.removeById(id, false);
        return deleteFlag?CommonHttpResult.success(id) : CommonHttpResult.success();
    }
    
}    


login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/js/jquery.min.js"></script>
</head>
<body>
<table border="1">

    <form action="/user/login" method="post">
        <tr>
            <td>账号:</td>
            <td><input id="userName" name="userName" type="text"></td>
            <td><input style="display: none" id="targetUrl" name="targetUrl" type="text" value="${targetUrl!}"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input id="password" name="password"  type="text"></td>
        </tr>
        <tr>
            <td colspan="2" style="text-align: center">
                <button id="loginBtn" type="submit">登录</button>
                <button id="logoutBtn" type="button" ><a href="/user/logout">退出</a></button>
            </td>
        </tr>


    </form>


</table>
<h1>当前用户:<span id="currentUser"></span></h1>
</body>
<script>

    $(function () {

        function getCookie(cookie_name) {
            var allcookies = document.cookie;
            //索引长度,开始索引的位置
            var cookie_pos = allcookies.indexOf(cookie_name);


            // 如果找到了索引,就代表cookie存在,否则不存在
            if (cookie_pos != -1) {
                // 把cookie_pos放在值的开始,只要给值加1即可
                //计算取cookie值得开始索引,加的1为“=”
                cookie_pos = cookie_pos + cookie_name.length + 1;
                //计算取cookie值得结束索引
                var cookie_end = allcookies.indexOf(";", cookie_pos);


                if (cookie_end == -1) {
                    cookie_end = allcookies.length;


                }
                //得到想要的cookie的值
                var value = unescape(allcookies.substring(cookie_pos, cookie_end));
            }
            return value;
        }


        $("#currentUser").text(getCookie("userName"));

    })

</script>

</html>
演示(Cookie认证-客户端)

未登录前

访问:http://localhost:8080/user/login
在这里插入图片描述

访问:http://localhost:8080/article-category/one/c08d391e02bc11eb9416b42e99ea3e62

在这里插入图片描述


登录时
在这里插入图片描述

Cookie信息存储会话标识(别称会话认证) - 认证信息存储在服务器内存中
讲解(会话认证)

小知识点: 服务器校验用户账号、密码即登录成功,一般会将用户信息存入服务器的session中,每次客户端请求都会携带会话标识即所谓ID,服务端根据这个ID找到具体的session,如果session中含有用户信息说明这个请求是有权限进行访问,进行后续的业务处理,session中没找到用户信息直接响应报文返回报错或者401

在这里插入图片描述


登录前请求响应
在这里插入图片描述


登录时的请求响应
在这里插入图片描述


登录后的请求响应 - 服务器根据sessionid判断他们的session会话是否有用户信息
在这里插入图片描述

实现(会话认证)
代码(会话认证)


文件结构
在这里插入图片描述


application.yml

server:
  port: 8080



# mybatisplus\u8BBE\u7F6E
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
    cache-enabled: true
  mapper-locations: classpath:mapper/*Mapper.xml
  global-config:
    db-config:
      id-type: assign_uuid
      logic-delete-value: 1
      logic-not-delete-value: 0
      logic-delete-field: is_del
      where-strategy: not_empty  #\u4E0Dwhere\u975Eempty\u7684\u5B57\u6BB5\u3010\u7A7A\u5B57\u7B26\u3001null\u503C\u3011
      update-strategy: not_empty
      insertStrategy: not_empty
spring:
  datasource:
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    username: root
    password: root
    url: jdbc:p6spy:mysql://localhost:3306/lrc_blog?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai



  freemarker:
    suffix: .html


SessionAuthInterceptor.java

package work.linruchang.qq.mybaitsplusjoin.config.interceptor;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.stream.Stream;

/**
 * 作用:cookie认证
 *
 * @author LinRuChang
 * @version 1.0
 * @date 2022/08/04
 * @since 1.8
 **/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SessionAuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        boolean authStatusFlag = false;

        //登录成功时用户信息都存入内存无需从数据库拿取
        HttpSession session = request.getSession();
        Dict sessionUser = (Dict) session.getAttribute("user");


        Cookie[] cookies = ObjectUtil.defaultIfNull(request.getCookies(), new Cookie[0]);
        String cookieUserName = Stream.of(cookies)
                .filter(cookie -> StrUtil.equals(cookie.getName(), "userName"))
                .findFirst()
                .map(Cookie::getValue)
                .orElse(null);


        if(ObjectUtil.isAllNotEmpty(sessionUser,cookieUserName)) {
            if(StrUtil.equals(sessionUser.getStr("userName"), cookieUserName)) {
                authStatusFlag = true;
            }
        }



        //认证失败 == 重定向到登录页面
        if (!authStatusFlag) {
            StringBuffer targetUrlUrl = request.getRequestURL();
            if (StrUtil.isNotBlank(request.getQueryString())) {
                targetUrlUrl.append("?");
                targetUrlUrl.append(request.getQueryString());
            }
            response.sendRedirect(StrUtil.format("/user2/login?targetUrl={}",targetUrlUrl));
        }

        return authStatusFlag;
    }
}


MyConfig.java

@Configuration
public class MyConfig implements WebMvcConfigurer {


    @Autowired
    SessionAuthInterceptor sessionAuthInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(sessionAuthInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/static/**","/user*/login/**","/user*/logout/**");
    }
}


ArticleCategoryController.java

@RestController
@RequestMapping("article-category")
public class ArticleCategoryController {

    @Autowired
    ArticleCategoryService articleCategoryService;

    /**
     * 根据ID进行查询
     * @param id
     * @return
     */
    @GetMapping("/one/{id}")
    public CommonHttpResult<ArticleCategory> findById(@PathVariable("id") String id) {
        return CommonHttpResult.success(articleCategoryService.getById(id));
    }

}


UserController2.java

@Controller
@RequestMapping("user2")
public class UserController2 {

    /**
     * 登录页面
     *
     * @param httpServletRequest
     * @param modelAndView
     * @return
     */
    @GetMapping("login")
    public ModelAndView loginPage(HttpServletRequest httpServletRequest, ModelAndView modelAndView) {
        modelAndView.setViewName("login2");
        modelAndView.addObject("targetUrl", httpServletRequest.getParameter("targetUrl"));
        return modelAndView;
    }

    /**
     * 登录
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param modelAndView
     */
    @PostMapping("login")
    @SneakyThrows
    //public void login(@RequestBody Dict loginInfo, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, ModelAndView modelAndView) {
    public void login(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, ModelAndView modelAndView) {
        String userName = httpServletRequest.getParameter("userName");
        String password = httpServletRequest.getParameter("password");
        String targetUrl = httpServletRequest.getParameter("targetUrl");

        if (StrUtil.equals(userName, "admin") && StrUtil.equals(password, "admin123")) {

            //String targetUrl = loginInfo.getTargetUrl();


            //自动会创建名字JSESSIONID的cookie用于标识会话
            //将所有涉及用户的信息都存储进内存session中
            HttpSession session = httpServletRequest.getSession();
            session.setAttribute("user", Dict.create()
                    .set("userName", "admin")
                    .set("password", "admin123"));


            //用户名-用于前端JS显示用户信息
            Cookie cookie = new Cookie("userName", "admin");
            cookie.setPath("/");
            cookie.setMaxAge(-1); //会话cookie
            httpServletResponse.addCookie(cookie);

            if (StrUtil.isNotBlank(targetUrl)) {
                httpServletResponse.sendRedirect(targetUrl);
            } else {
                httpServletResponse.setHeader("Content-Type", "application/json;charset=UTF-8");
                httpServletResponse.getWriter().print(JSONUtil.toJsonStr(CommonHttpResult.success("登录成功")));
            }
        } else {
            httpServletResponse.sendRedirect(StrUtil.format("login?targetUrl={}", targetUrl));
        }

    }

    /**
     * 退出登录 == 命令浏览器删除cookie
     *
     * @return
     */
    @GetMapping("logout")
    public String logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        //userName cookie过期
        Cookie userNameCookie = new Cookie("userName", null);
        userNameCookie.setPath("/");
        userNameCookie.setMaxAge(0);
        httpServletResponse.addCookie(userNameCookie);

        //session会话过期
        HttpSession session = httpServletRequest.getSession();
        session.invalidate();


        return "redirect:/user2/login";
    }

}


login2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/js/jquery.min.js"></script>
</head>
<body>
<table border="1">

    <form action="/user2/login" method="post">
        <tr>
            <td>账号:</td>
            <td><input id="userName" name="userName" type="text"></td>
            <td><input style="display: none" id="targetUrl" name="targetUrl" type="text" value="${targetUrl!}"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input id="password" name="password"  type="text"></td>
        </tr>
        <tr>
            <td colspan="2" style="text-align: center">
                <button id="loginBtn" type="submit">登录</button>
                <button id="logoutBtn" type="button" ><a href="/user2/logout">退出</a></button>
            </td>
        </tr>


    </form>


</table>
<h1>当前用户:<span id="currentUser"></span></h1>
</body>
<script>

    $(function () {

        function getCookie(cookie_name) {
            var allcookies = document.cookie;
            //索引长度,开始索引的位置
            var cookie_pos = allcookies.indexOf(cookie_name);


            // 如果找到了索引,就代表cookie存在,否则不存在
            if (cookie_pos != -1) {
                // 把cookie_pos放在值的开始,只要给值加1即可
                //计算取cookie值得开始索引,加的1为“=”
                cookie_pos = cookie_pos + cookie_name.length + 1;
                //计算取cookie值得结束索引
                var cookie_end = allcookies.indexOf(";", cookie_pos);


                if (cookie_end == -1) {
                    cookie_end = allcookies.length;


                }
                //得到想要的cookie的值
                var value = unescape(allcookies.substring(cookie_pos, cookie_end));
            }
            return value;
        }


        $("#currentUser").text(getCookie("userName"));

    })

</script>

</html>
演示(会话认证)

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值