Spring Security基础:快速搭建安全认证系统

深巷里的服务器
2025-06-18 10:49
阅读 725

开篇:什么是Spring Security,它有什么用?

开篇:什么是Spring Security,它有什么用?

在当今的Web开发中,安全性是一个非常重要的问题。用户登录、权限控制、数据保护——这些都离不开一个强大的安全框架。Spring Security 就是这样一个专门为Java开发者提供的、用来保护Web应用的强大工具。

你可以把 Spring Security 想象成你网站的“保安”。它的工作就是:

  • 验证谁有资格访问你的系统(比如谁可以登录)
  • 管理每个用户能做什么事(比如普通用户只能看信息,管理员可以删数据)
  • 保护敏感操作不被恶意攻击(防止他人暴力破解、跨站请求伪造等)

我们今天要做的,就是从零开始,带着你一步步搭建一个最简单的基于Spring Security的安全认证系统。


环境准备:你需要安装什么?

环境准备:你需要安装什么?

为了学习本教程,你需要准备好以下环境:

软件清单:

软件 版本建议 下载地址
Java JDK 17 或更高 Oracle官网
IntelliJ IDEA(推荐) 社区版即可 JetBrains官网
Maven 最新稳定版(IDEA内置) 无需单独下载
浏览器 Chrome 或 Edge 推荐 常规浏览器即可

服务器部署方案-1

✅ 小提示:如果你使用的是Mac或Linux系统,请确认终端中执行 java -versionmvn -v 命令是否输出版本号。

创建Spring Boot项目(使用Spring Initializr)

我们通过Spring Initializr来创建一个基础Spring Boot项目:

  1. 打开链接,选择:
    • Project: Maven
    • Language: Java
    • Spring Boot Version: 3.x (如3.2.4)
    • Group: com.example
    • Artifact: demo-security
    • Name: demo-security
    • Packaging: Jar
    • Java Version: 17
  2. 在"Dependencies"搜索栏中添加两个依赖:
    • Spring Web
    • Spring Security
  3. 点击按钮 “Generate” 下载项目压缩包
  4. 解压并导入到IDEA或你使用的Java IDE中

核心概念:Spring Security中的几个关键角色和功能

核心概念:Spring Security中的几个关键角色和功能

在正式动手之前,先了解几个核心概念,帮你更好地理解代码背后的逻辑。

1. 用户(User)

指的是使用你系统的访客,可能是注册用户或者游客。Spring Security可以让你为不同用户设置不同的权限。

✅ 示例:张三(普通用户),李四(管理员)

2. 权限(Authority / Role)

权限就是用户被允许做的事情。

  • ROLE_ADMIN 表示管理员角色
  • ROLE_USER 表示普通用户角色
  • READ_ONLY 表示只读权限

你也可以自己定义权限,例如 ORDER_READ、CUSTOMER_EDIT 等。

3. 认证(Authentication)

就是验证你是谁的过程。通常表现为用户名 + 密码的登录方式。

✅ 相当于身份证检查过程。

4. 授权(Authorization)

确定你有权访问某些资源或执行某项操作。

✅ 类似安检后的通行证发放,不是所有区域都能进。

5. Security配置类

你需要通过一个配置类告诉Spring Security:

  • 哪些页面需要登录?
  • 使用哪种认证机制?
  • 如何处理登录失败?

这是整个安全机制的核心配置。


实战项目:一步步实现基础安全认证系统

实战项目:一步步实现基础安全认证系统

我们将从零开始,完成如下功能:

  1. 创建一个登录页面
  2. 实现基本的用户登录验证
  3. 区分普通用户和管理员的不同权限
  4. 实现退出登录功能

第一步:启动Spring Boot项目

确保你已经将项目导入IDE,并成功运行起来。默认情况下,Spring Security会在启动时自动生成一个随机密码,格式类似:

Using default security password: abcdefghijklmnopqrstuvwxyz1234567890

这在测试期间很管用,但我们很快就会用自己的账户管理替代它。


第二步:自定义用户账户(内存中模拟数据库)

我们在src/main/java/com/example/demosecurity/目录下新建一个配置类:SecurityConfig.java

package com.example.demosecurity;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    // 定义用户账号(存在内存中用于演示)
    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("user")
                .password("123456")
                .roles("USER")
                .build();

        UserDetails admin = User.withDefaultPasswordEncoder()
                .username("admin")
                .password("123456")
                .roles("ADMIN")
                .build();

        return new InMemoryUserDetailsManager(user, admin);
    }

    // 安全策略配置
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/").permitAll()
                .requestMatchers("/user/**").hasRole("USER")
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(login -> login
                .loginPage("/login")  // 自定义登录页路径
                .permitAll()
            )
            .logout(logout -> logout
                .permitAll()
            );
        
        return http.build();
    }
}

🧠 小解释:

  • InMemoryUserDetailsManager:把用户保存在内存里,适合初学者模拟测试。
  • .formLogin():启用基于表单的登录方式。
  • .authorizeHttpRequests():指定哪些URL需要什么权限才能访问。
  • .requestMatchers():匹配特定路径,.anyRequest()表示其他所有未明确设定的请求都需要登录才能访问。

第三步:创建控制器Controller

新建文件 HomeController.java

package com.example.demosecurity;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

    @GetMapping("/")
    public String index() {
        return "index";
    }

    @GetMapping("/user/home")
    public String userHome() {
        return "user_home";
    }

    @GetMapping("/admin/dashboard")
    public String adminDashboard() {
        return "admin_dashboard";
    }

    @GetMapping("/login")
    public String loginPage() {
        return "login"; // 返回视图名称
    }
}

这段代码只是简单地映射几个页面路径,后续我们会为其添加HTML视图。


第四步:添加Thymeleaf模板(前端页面)

我们要显示登录页面和主页,所以需要使用模板引擎。Spring Boot默认支持Thymeleaf。

pom.xml 中加入 Thymeleaf 的依赖(如果还没有):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

然后在 src/main/resources/templates 文件夹中创建以下HTML文件:

login.html(登录页面)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>登录页面</title>
</head>
<body>
    <h2>请登录</h2>
    <form th:action="@{/login}" method="post">
        <div>
            <label>用户名:
                <input type="text" name="username"/>
            </label>
        </div>
        <div>
            <label>密码:
                <input type="password" name="password"/>
            </label>
        </div>
        <div>
            <button type="submit">登录</button>
        </div>
    </form>
</body>
</html>

index.html(主页)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>首页</title>
</head>
<body>
    <h1>欢迎来到首页!</h1>
    <p>您可以尝试访问:</p>
    <ul>
        <li><a href="/user/home">用户空间</a></li>
        <li><a href="/admin/dashboard">管理员仪表板</a></li>
    </ul>
</body>
</html>

user_home.html(普通用户页面)

<h1>用户页面</h1>
<p>这里是普通用户可以看到的内容。</p>

admin_dashboard.html(管理员页面)

<h1>管理员仪表盘</h1>
<p>只有管理员才能看到这里哦。</p>

第五步:运行项目并测试访问

现在启动Spring Boot项目,在浏览器中打开:

http://localhost:8080

你应该能看到欢迎首页,点击链接尝试访问 /user/home/admin/dashboard

尝试登录:

  • 用户名:user / 密码:123456
  • 用户名:admin / 密码:123456

登录后,会跳转到对应的页面;否则返回登录页。


常见问题解答

Q1:登录后总是跳回登录页面怎么办?

一般是由于没有正确提交表单或没有正确配置登录页面路径导致。

✅ 检查点:

  • 登录表单必须使用 POST 提交
  • 表单字段必须命名为 usernamepassword
  • controller 中确实有 /login 页面返回

Q2:如何修改默认的登录路径 /login

可以在配置类中使用 .loginProcessingUrl("/my-login") 来指定新的登录处理路径。

示例代码片段:

.formLogin(login -> login
    .loginPage("/custom-login")
    .loginProcessingUrl("/my-login")  // 修改这个处理路径
    .permitAll()
)

同时也要调整前端登录表单 action 地址:

<form th:action="@{/my-login}" method="post">

Q3:Spring Security报错:“Invalid CSRF token found in form”

这是因为在Spring Security中启用了CSRF(跨站请求伪造)防护,默认需要配合令牌一起提交。

✅ 初学阶段可以暂时禁用CSRF(仅限测试):

.http.csrf(csrf -> csrf.disable())  // 不推荐用于生产环境!

⚠️ 注意:生产环境中应保留CSRF防护措施,并正确生成和验证token。


Q4:我如何查看当前登录的用户信息?

Spring Security提供了一个方便的工具类可以获取用户信息:

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

    @GetMapping("/user/me")
    public String showMe(Authentication authentication, Model model) {
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        model.addAttribute("username", userDetails.getUsername());
        return "user_info";
    }
}

然后在HTML中显示:

<h2>你好,<span th:text="${username}"></span>!</h2>

学习建议:下一步学什么?

恭喜你完成了第一个Spring Security认证系统!

接下来你可能想继续深入了解以下几个方向:

1. 数据库连接用户认证(JDBC or JPA)

目前我们都是使用内存中的用户,真正的项目需要用数据库来存储用户信息。

相关知识点:

  • JdbcUserDetailsManager
  • 数据库表结构设计
  • 用户密码加密(BCrypt)

2. 基于角色的权限控制(RBAC)

更复杂的权限体系需要用到角色继承、菜单权限等功能。

3. OAuth2 / JWT 支持移动端或前后端分离

如果你打算做API接口给手机App使用,可进一步学习JWT与OAuth2协议。

4. 方法级权限控制(@PreAuthorize)

不仅能控制访问哪个页面,还能控制调用某个方法的权限。

5. 多因子认证、登出行为、日志审计等

这些都是企业级项目中常见的高级安全需求。


总结

数据流转过程-2

本文带你在没有任何Spring Security经验的情况下,一步步搭建了一个基础的身份认证系统。我们讲解了:

  • Spring Security是什么
  • 如何配置基本认证流程
  • 如何区分用户权限
  • 如何处理常见问题

希望你能根据这篇文章动手实践,亲手写出属于自己的安全认证模块。随着你对Spring Security的深入学习,你会发现它的强大远不止于此。

加油!编程世界的大门为你敞开😊

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝