19《Spring Boot 入门教程》Spring Boot 使用拦截器

1. 前言

拦截器这个名词定义的非常形象,就像导弹要攻击目标的时候,可能会被先进的反导系统拦截,此处的反导系统就是一种拦截器。

我们开发的应用,对外暴露的是控制器中定义的 API 方法,我们可以在 API 方法的外围放置拦截器,所有对 API 的访问都可以通过拦截器进行过滤。

OK,那么这样的拦截有什么意义吗,其实已经很明显了,反导系统可以保护目标的安全并识别对目标的攻击行为。同理,拦截器可以跟踪对应用的访问行为,对合法访问行为予以放行,对非法访问行为予以拒绝。怎么样,是不是很牛,接下来咱们就在 Spring Boot 项目中具体实现下。

2. 跟踪访问行为

要想实现对访问的拦截,首先要能跟踪访问行为,我们在 Spring Boot 中引入拦截器来实现下。

2.1 使用 Spring Initializr 创建项目

Spring Boot 版本选择 2.2.5 ,Group 为 com.imooc , Artifact 为 spring-boot-interceptor ,生成项目后导入 Eclipse 开发环境。

2.2 引入项目依赖

引入 Web 项目依赖即可。

实例:

        <!-- web项目依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

2.3 创建拦截器

创建的类实现 HandlerInterceptor 接口,即可成为拦截器类.

实例:

/**
 * 自定义拦截器类
 */
public class MyInterceptor implements HandlerInterceptor {// 实现HandlerInterceptor接口
    /**
     * 访问控制器方法前执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println(new Date() + "--preHandle:" + request.getRequestURL());
        return true;
    }

    /**
     * 访问控制器方法后执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println(new Date() + "--postHandle:" + request.getRequestURL());
    }

    /**
     * postHandle方法执行完成后执行,一般用于释放资源
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println(new Date() + "--afterCompletion:" + request.getRequestURL());
    }
}

在上面的实例中,我们定义了一个拦截器类 MyInterceptor ,通过实现 HandlerInterceptor 接口,该类具备了拦截器的功能。

MyInterceptor 中的方法执行顺序为 preHandle – Controller 方法 – postHandle – afterCompletion ,所以拦截器实际上可以对 Controller 方法执行前后进行拦截监控。

最后还有一个非常重要的注意点, preHandle 需要返回布尔类型的值。 preHandle 返回 true 时,对控制器方法的请求才能到达控制器,继而到达 postHandle 和 afterCompletion 方法;如果 preHandle 返回 false ,后面的方法都不会执行。

2.4 配置拦截器

上一步我们开发了配置器类,如果想让配置器生效,还需要通过配置类进行相应配置。

实例:

/**
 * Web配置类
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    /**
     * 添加Web项目的拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 对所有访问路径,都通过MyInterceptor类型的拦截器进行拦截
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

2.5 创建控制器

我们建立一个简单的控制器,实现登录方法,以便检验拦截器的效果。

实例:

/**
* 登录控制器
*/
@RestController
public class LoginController {
   @RequestMapping("/login")
   public boolean login(String username, String password) {
    System.out.println(new Date() + " 某用户尝试登录,用户名:" + username + " 密码:" + password);
    return true;
   }
}

2.6 跟踪访问行为

运行启动类,访问 http://127.0.0.1:8080/login?username=imooc&password=123,控制台输出如下:

5ec0be6609d24ee807400125.jpg

控制台输出内容

可见我们已经完整的跟踪了一次对 http://127.0.0.1:8080/login 接口的访问。

3. 实现访问控制

区分合法、非法访问,最常见的就是根据用户的登录状态、角色判断。接下来我们就演示下,对未登录用户非法访问请求的拦截。

3.1 修改控制器方法

修改登录方法,当用户输入的用户名和密码正确时,通过 Session 记录登录人信息。

然后开发获取登录人员信息方法,返回 Session 中记录的登录人信息。

实例:

/**
 * 登录控制器
 */
@RestController
public class LoginController {
    /**
     * 登录方法
     */
    @RequestMapping("/login")
    public boolean login(HttpServletRequest request, String username, String password) {
        if ("imooc".equals(username) && "123".equals(password)) {
            // 登录成功,则添加Session并存储登录用户名
            request.getSession().setAttribute("LOGIN_NAME", username);
            return true;
        }
        return false;
    }

    /**
     * 获取登录人员信息
     */
    @RequestMapping("/info")
    public String info(HttpServletRequest request) {
        return "您就是传说中的:" + request.getSession().getAttribute("LOGIN_NAME");
    }
}

3.2 修改拦截器方法

由于用户在登录之前还没有设置 Session ,所以登录方法不应该拦截,可以让用户自由请求。但是只有登录成功后的用户,也就是说具备 Session 的用户才能访问 info 方法。

实例:

/**
 * 自定义拦截器类
 */
public class MyInterceptor implements HandlerInterceptor {// 实现HandlerInterceptor接口
    /**
     * 访问控制器方法前执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (request.getRequestURI().contains("/login") == true) {// 登录方法直接放行
            return true;
        } else {// 其他方法需要先检验是否存在Session
            if (request.getSession().getAttribute("LOGIN_NAME") == null) {//未登录的不允许访问
                return false;
            } else {
                return true;
            }
        }
    }
}

3.3 测试

首先直接请求 http://127.0.0.1:8080/info ,由于此时未登录,所以请求被拦截,网页输出如下:

5ec0c33709148c4807410110.jpg

访问被拦截

如果先请求登录方法 http://127.0.0.1:8080/login?username=imooc&password=123 ,然后访问 http://127.0.0.1:8080/info ,则网页输出:

5ec0c3970917c0bc07430112.jpg

登录成功后,访问正常通过拦截器

4. 小结

Spring Boot 的拦截器能够管理对控制器方法的访问请求,通过使用拦截器,可以实现访问控制,加强项目的安全性。

当然对于更加复杂的安全管理续期, Spring Boot 也可以快速的整合 Spring Security 或 Shiro ,以构建企业级的安全管理体系,在后续章节再进一步介绍吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容