赞
踩
参考文章: https://blog.csdn.net/qq_35642036/article/details/82788588
注意: 登录成功时的响应报文头会多了个Set-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
文件结构
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>
未登录前
访问:http://localhost:8080/user/login
访问:http://localhost:8080/article-category/one/c08d391e02bc11eb9416b42e99ea3e62
登录时
小知识点: 服务器校验用户账号、密码即登录成功,一般会将用户信息存入服务器的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>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。