星光不问赶路人,时光不负有心人。
目录
- 前言
- 环境准备
- 拦截器的实现
- 强制用户登录
- 记住我
前言
关于如何搭建SpringBoot工程以及开启Web功能,
可以查看我的这篇博客:用Spring Initializr快速构建SpringBoot及整合MVC
环境准备
先来确保一下环境配置没有问题。在依赖管理文件pom.xml
中要有热部署的依赖spring-boot-devtools
(点击进入热部署配置),MVC的起步依赖spring-boot-starter-web
,Thymeleaf的起步依赖spring-boot-starter-thymeleaf
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
其次,在配置文件application.yml
中关闭Thymeleaf的页面缓存:
spring:
thymeleaf:
cache: false
请注意:这里的视图技术用的是SpringBoot官方推荐的Thymeleaf而不是JSP
点击进入 SpringBoot三步整合Thymeleaf模板技术
接下来,我们在工程目录src/main/resources/templates下,新建一个首页index.hmtl
和登录页面login.html
:
其中,首页index.html
代码为:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>你好, 古阙月! 这是首页</h1>
</body>
</html>
登陆页面login.html
代码为:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hi, 古阙月, 欢迎登录!</h1>
</body>
</html>
再配置一下login.html
的访问路径,新建一个配置类实现WebMvcConfigurer接口,再按住快捷键Ctrl + O(不是零是欧),重写其中的addViewControllers()方法,如:
package com.guqueyue.controller.config;
/**
* @author guqueyue
* @Date 2020/4/27
* 配置类
**/
@Configuration //表示当前类是配置相关的
public class WebConfig implements WebMvcConfigurer {
/**
* 用页面和地址做一个映射关系来实现页面跳转
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 跳转方式为:转发; 第一个参数为路径, 第二个参数为视图路径名称
registry.addViewController("/login").setViewName("login");
}
}
我们都知道,直接访问系统会默认跳转到index.html
的页面,如:启动程序,浏览器输入"http://localhost:8080":
那么,我们可不可以写一个拦截器,在访问首页时拦截到访问登录页面呢?
拦截器的实现
有时候为了拦截掉垃圾访问;又或者为了安全着想,有些路径必须通过认证之类的操作才能访问,这个时候一个拦截器是必不可少的。
首先,我们新建一个类,实现HandlerInterceptor
接口,并重写接口里的方法:
package com.guqueyue.interceptor;
/**
* @author guqueyue
* @Date 2020/4/27
* 登录拦截
**/
public class LoginInterceptor implements HandlerInterceptor {
/**
* 可以做业务判断选择放行、拦截或者进行其他操作
* @param request
* @param response
* @param handler
* @return false 表示拦截, true 表示放行
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 转发页面到登录页面
request.getRequestDispatcher("/login").forward(request, response);
return false;
}
}
再在原来实现了WebMvcConfigurer
接口的配置类中,Ctrl + O
重写addInterceptors()
方法来配置拦截器:
package com.guqueyue.config;
/**
* @author guqueyue
* @Date 2020/4/27
* 配置类
**/
@Configuration //表示当前类是配置相关的
public class WebConfig implements WebMvcConfigurer {
/**
* 用页面和地址做一个映射关系来实现页面跳转
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 跳转方式为:转发; 第一个参数为路径, 第二个参数为视图路径名称
registry.addViewController("/login").setViewName("login");
}
/**
* 配置拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
// 被拦截路径
.addPathPatterns("/**")
// 忽略路径, 通常我们需要忽略掉一些静态资源
.excludePathPatterns("/login", "/**/**.js", "/**/*.css", "/**/*.png ", "/**/*.jpg", "/**/*.gif ");
}
}
到这里也就配置完成了!
当然也可以参照我的这篇博客:SpringBoot一步配置Filter 利用Java匿名内部类的特性,直接用一个方法进行配置!
因为配置了热部署所以无需重启程序,直接刷新浏览器显示:
说明拦截成功!但是记得一定要放行登录页面也就是忽略登录的路径,不然又跳转到登录页面,又进行拦截,是会报错的:
当然,在实际的开发过程中,我们要根据自己的业务需求来选择忽略路径或者拦截路径。比如,CSDN未登录可以浏览文章,但是如果要进入创造中心就:
强制用户登录
那么回到我们标题的后半部分:强制用户登录是怎么做到的?毕竟按照我们之前编写代码的逻辑,系统只会不停的跳转到登录页面,这样根本没法玩呀!其实我们只需要二步即可:
在用户成功登录时,将用户信息存储到Cookie或者Session
在拦截器中判断是否登录,也就是Cookie或者Session是否有登录信息。若是有,则放行;反之,则拦截回登录页面。
如,在判断用户登录成功后,将用户信息存储到Cookie中:
// 如果用户登录成功,则将用户信息存入cookie
Cookie cookie = new Cookie("loginName", username);
// 设置cookie的最大存活时间,单位秒
cookie.setMaxAge(60 * 60 * 24 * 7);
// 设置路径
cookie.setPath("/");
// 域名
cookie.setDomain("localhost");
// 将浏览器写入cookie
response.addCookie(cookie);
再去拦截器中的preHandle()
方法中判断,是否有存入了用户信息。若是有,放行;若是无,拦截即可:
// 取出cookie中的信息,判断有没有登录
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
// 若登录,放行
if (cookie.getName().equals("loginName")) {
return true;
}
}
}
// 未登录,拦截到登录页面
request.getRequestDispatcher("/login").forward(request, response);
return false;
当然,在实际开发中可能没那么简单。可能是将随机生成一个UUID作为token
,然后将这个token
和用户对象以key-value的形式存入redis数据库中,然后将这个token
存入Cookie:
//登录成功,将用户信息写入redis
String token = UUID.randomUUID().toString();
redisTemplate.opsForValue().set(token, user);
redisTemplate.expire(token, 7, TimeUnit.DAYS);
//将uuid写入cookie
Cookie cookie = new Cookie("login_token", token);
//设置cookie的最大存活时间,如果不设置,默认浏览器关闭就没有了,单位是秒
cookie.setMaxAge(60 * 60 * 24 * 7);
// 设置路径
cookie.setPath("/");
// 域名
cookie.setDomain("localhost");
//将cookie写入浏览器 - Response
response.addCookie(cookie);
然后去通过这个login_token
在Cookie中取出token
,再通过这个token
去redis数据库中取出用户信息判断是否登录:
// 取出cookie中的信息
String token = null;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
// 若登录,放行
if (cookie.getName().equals("login_token")) {
token = cookie.getValue();
}
}
}
// 通过token去redis数据库中取出用户信息,判断是否登录
if(token!= null){
//去redis中验证是否登录
User user = (User) redisTemplate.opsForValue().get(token);
if(user != null) {
//已经登录,则放行
return true;
}
}
// 未登录,拦截到登录页面
request.getRequestDispatcher("/login").forward(request, response);
return false;
当然,方法五花八门,只要实现了功能就好,诸位还请八仙过海 —— 各显神通吧。
记住我
我们经常在登录网站的时候,看到记住我这个选项,比如b站:
实现记住我可以让自己在很长一段时间内保持登录状态,之前在《强制用户登录》章节我们的操作其实是默认记住我,并且时间为一周。当然正如b站提示的那样:不是自己的电脑不要勾选此选项
。所以,我们只要判断有没有勾选记住我即可,若是没有记住我,则不要设置Cokkie的最大存活时间。这样Cookie的存活时间默认为会话级别,也就是浏览器关闭就没了。反之,若是勾选了记住我,设置Cookie的最大存活时间即可,比如:
cookie.setMaxAge(60 * 60 * 24 * 7);