当前位置: 首页 > news >正文

Spring Boot中的过滤器与拦截器实战:实现用户认证与资源访问控制

源访问控制

概述

在构建Web应用时,我们经常需要实现诸如用户认证、资源访问控制等功能。Spring Boot 提供了多种工具来帮助开发者轻松实现这些需求。本文将介绍如何使用Spring Boot 3.x中的过滤器(Filter)和拦截器(Interceptor)来实现用户登录验证和对特定资源的访问控制。

技术栈

  • Spring Boot 3.x
  • Spring Security
  • Spring Web
  • Lombok
  • Thymeleaf

业务需求

假设我们需要构建一个简单的博客平台,用户需要登录后才能发表评论或查看私人文章。为了实现这一需求,我们需要:

  1. 在用户尝试访问需要登录的功能时进行身份验证。
  2. 对特定资源(如私人文章)进行访问控制。

步骤详解

1. 配置Spring Security

首先,在WebSecurityConfig类中配置Spring Security来处理基本的身份验证和授权。

java

深色版本

1package com.example.blogapp.config;
2
3import org.springframework.context.annotation.Bean;
4import org.springframework.context.annotation.Configuration;
5import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
7import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
8import org.springframework.security.crypto.password.PasswordEncoder;
9import org.springframework.security.web.SecurityFilterChain;
10
11@Configuration
12@EnableWebSecurity
13public class WebSecurityConfig {
14
15    @Bean
16    public PasswordEncoder passwordEncoder() {
17        return new BCryptPasswordEncoder();
18    }
19
20    @Bean
21    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
22        http
23            .authorizeHttpRequests((authz) -> authz
24                .requestMatchers("/private/**").authenticated()
25                .anyRequest().permitAll()
26            )
27            .formLogin(form -> form
28                .loginPage("/login")
29                .permitAll()
30            )
31            .logout(logout -> logout
32                .permitAll()
33            );
34        return http.build();
35    }
36}

2. 实现过滤器

接下来,创建一个过滤器来处理登录请求前后的操作,例如记录登录日志。

java

深色版本

1package com.example.blogapp.filter;
2
3import javax.servlet.FilterChain;
4import javax.servlet.ServletException;
5import javax.servlet.ServletRequest;
6import javax.servlet.ServletResponse;
7import javax.servlet.http.HttpServletRequest;
8import javax.servlet.http.HttpServletResponse;
9import java.io.IOException;
10
11public class AuthFilter implements javax.servlet.Filter {
12
13    @Override
14    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
15            throws IOException, ServletException {
16        HttpServletRequest httpRequest = (HttpServletRequest) request;
17        HttpServletResponse httpResponse = (HttpServletResponse) response;
18
19        System.out.println("AuthFilter: Pre-processing for request to " + httpRequest.getRequestURI());
20
21        chain.doFilter(request, response);
22
23        System.out.println("AuthFilter: Post-processing for request to " + httpRequest.getRequestURI());
24    }
25}

在web.xml文件中配置过滤器:

xml

深色版本

1<filter>
2    <filter-name>authFilter</filter-name>
3    <filter-class>com.example.blogapp.filter.AuthFilter</filter-class>
4</filter>
5
6<filter-mapping>
7    <filter-name>authFilter</filter-name>
8    <url-pattern>/login</url-pattern>
9</filter-mapping>

3. 实现拦截器

然后,创建一个拦截器来控制对私人文章页面的访问。如果用户未登录,则重定向到登录页面。

java

深色版本

1package com.example.blogapp.interceptor;
2
3import org.springframework.stereotype.Component;
4import org.springframework.web.servlet.HandlerInterceptor;
5import org.springframework.web.servlet.ModelAndView;
6
7import javax.servlet.http.HttpServletRequest;
8import javax.servlet.http.HttpServletResponse;
9
10@Component
11public class AccessControlInterceptor implements HandlerInterceptor {
12
13    @Override
14    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
15            throws Exception {
16        if (request.getSession(false).getAttribute("user") == null) {
17            response.sendRedirect("/login");
18            return false;
19        }
20        return true;
21    }
22
23    @Override
24    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
25                           ModelAndView modelAndView) throws Exception {
26        // 可以在这里添加一些额外的处理逻辑
27    }
28
29    @Override
30    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
31            throws Exception {
32        // 可以在这里添加一些清理逻辑
33    }
34}

在WebMvcConfigurer中注册拦截器:

java

深色版本

1package com.example.blogapp.config;
2
3import org.springframework.context.annotation.Configuration;
4import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
5import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
6
7@Configuration
8public class WebMvcConfig implements WebMvcConfigurer {
9
10    @Override
11    public void addInterceptors(InterceptorRegistry registry) {
12        registry.addInterceptor(new AccessControlInterceptor())
13                .addPathPatterns("/private/**")
14                .excludePathPatterns("/login");
15    }
16}

4. 创建控制器

接下来,定义两个控制器:一个用于处理登录流程,另一个用于展示私人文章。

java

深色版本

1package com.example.blogapp.controller;
2
3import org.springframework.security.core.Authentication;
4import org.springframework.security.core.context.SecurityContextHolder;
5import org.springframework.stereotype.Controller;
6import org.springframework.ui.Model;
7import org.springframework.web.bind.annotation.GetMapping;
8import org.springframework.web.bind.annotation.PostMapping;
9
10@Controller
11public class AuthController {
12
13    @GetMapping("/login")
14    public String showLoginPage() {
15        return "login";
16    }
17
18    @PostMapping("/login")
19    public String handleLogin() {
20        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
21        if (authentication != null && authentication.isAuthenticated()) {
22            return "redirect:/private/posts";
23        } else {
24            return "redirect:/login?error";
25        }
26    }
27}
java

深色版本

1package com.example.blogapp.controller;
2
3import org.springframework.security.core.Authentication;
4import org.springframework.security.core.context.SecurityContextHolder;
5import org.springframework.stereotype.Controller;
6import org.springframework.ui.Model;
7import org.springframework.web.bind.annotation.GetMapping;
8
9@Controller
10public class PostController {
11
12    @GetMapping("/private/posts")
13    public String showPrivatePosts(Model model) {
14        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
15        model.addAttribute("user", authentication.getName());
16        return "private-post";
17    }
18}

5. 页面模板

创建登录页面和私人文章页面的HTML模板。

html

深色版本

1<!-- src/main/resources/templates/login.html -->
2<!DOCTYPE html>
3<html xmlns:th="http://www.thymeleaf.org">
4<head>
5    <title>Login Page</title>
6</head>
7<body>
8    <h1>Login</h1>
9    <form th:action="@{/login}" method="post">
10        <label for="username">Username:</label>
11        <input type="text" id="username" name="username" required/>
12        <br/>
13        <label for="password">Password:</label>
14        <input type="password" id="password" name="password" required/>
15        <br/>
16        <input type="submit" value="Login"/>
17    </form>
18</body>
19</html>
html

深色版本

1<!-- src/main/resources/templates/private-post.html -->
2<!DOCTYPE html>
3<html xmlns:th="http://www.thymeleaf.org">
4<head>
5    <title>Private Posts</title>
6</head>
7<body>
8    <h1>Welcome, <span th:text="${user}"></span></h1>
9    <p>This is your private posts page.</p>
10</body>
11</html>

运行应用

启动应用后,尝试访问
http://localhost:8080/private/posts,系统会自动重定向到登录页面。登录成功后,将可以看到私人文章页面。

结论

通过以上步骤,我们实现了基于Spring Boot的用户认证和资源访问控制。这种方式结合了Spring Security、过滤器和拦截器的强大功能,为我们的应用提供了安全性和灵活性。这种架构模式可以很容易地扩展到更复杂的业务场景中,例如多角色权限管理、审计日志记录等。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 无法找到模块“vuex”的声明文件。“../node_modules/vuex/dist/vuex.mjs”隐式拥有 “any“ 类型。
  • 使用uart串口配置TMC2209模块
  • [Matsim]Matsim学习笔记-population.xml的创建
  • flv和 rtmp视频负载类型的差异
  • 机器人拾取系统关节机械臂通过NY-PN-EIPZ进行命令控制
  • PCIe学习笔记(27)
  • 2024年中科院SCI期刊牛顿-拉夫逊优化算法NRBO优化Transformer-LST模型的多变量时间序列预测
  • 【Harmony OS 4.0】像素单位 - px、vp、fp
  • 基于SpringBoot的网上宠物店系统
  • C语言:函数详解(2)
  • C++如何为枚举量生成对应的解释:4种常见的方法
  • 探索宝可梦的世界:PokeAPI如何让开发者大展拳脚
  • 【Spring Cloud】Consul
  • 深入理解 Go 语言并发编程--管道(channel) 的底层原理
  • 分布式 - 主从复制技术详解及时延处理
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • [Vue CLI 3] 配置解析之 css.extract
  • 07.Android之多媒体问题
  • download使用浅析
  • ES学习笔记(12)--Symbol
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • Java编程基础24——递归练习
  • Rancher-k8s加速安装文档
  • use Google search engine
  • Vue.js-Day01
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 深度学习在携程攻略社区的应用
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 微信小程序开发问题汇总
  • 鱼骨图 - 如何绘制?
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • elasticsearch-head插件安装
  • ​Java并发新构件之Exchanger
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ​批处理文件中的errorlevel用法
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • (2024最新)CentOS 7上在线安装MySQL 5.7|喂饭级教程
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第2节(泛型类的类构造函数)
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (php伪随机数生成)[GWCTF 2019]枯燥的抽奖
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (备忘)Java Map 遍历
  • (回溯) LeetCode 46. 全排列
  • (十六)Flask之蓝图
  • (转载)hibernate缓存
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .net 后台导出excel ,word
  • .Net 基于.Net8开发的一个Asp.Net Core Webapi小型易用框架
  • .NET 项目中发送电子邮件异步处理和错误机制的解决方案
  • .NET业务框架的构建
  • @Mapper作用
  • @PostConstruct 注解的方法用于资源的初始化
  • @RequestBody与@ResponseBody的使用