SpringBoot拦截器的配置:强制用户登录是怎么做到的?

星光不问赶路人,时光不负有心人。

前言

关于如何搭建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":
在这里插入图片描述
那么,我们可不可以写一个拦截器,在访问首页时拦截到访问登录页面呢?

扫描二维码关注公众号,回复: 11373525 查看本文章

拦截器的实现

有时候为了拦截掉垃圾访问;又或者为了安全着想,有些路径必须通过认证之类的操作才能访问,这个时候一个拦截器是必不可少的。

首先,我们新建一个类,实现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未登录可以浏览文章,但是如果要进入创造中心就:在这里插入图片描述

强制用户登录

那么回到我们标题的后半部分:强制用户登录是怎么做到的?毕竟按照我们之前编写代码的逻辑,系统只会不停的跳转到登录页面,这样根本没法玩呀!其实我们只需要二步即可:

  1. 在用户成功登录时,将用户信息存储到Cookie或者Session
  2. 在拦截器中判断是否登录,也就是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);

猜你喜欢

转载自blog.csdn.net/Qizhi_Hu/article/details/105787719