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

贪心没贪够
2025-06-24 22:09
阅读 288

开篇:Spring Security是什么,用来做什么?

开篇:Spring Security是什么,用来做什么?

你是否曾好奇,为什么我们登录一个网站时,系统会记住你是谁?为什么某些页面你没权限就打不开?这背后其实有一整套“安全验证”的逻辑在起作用。而 Spring Security 就是 Java 开发中最常用于实现这套安全验证机制的框架。

简单来说,Spring Security 就是用来保护你的网页或接口不被随便访问的一把“锁”。它可以帮助你实现:

  • 用户登录功能(认证)
  • 不同用户有不同访问权限(授权)
  • 防止攻击行为(比如暴力破解、跨站脚本等)

在这篇教程中,我会带大家从零开始,一步步用 Spring Security 搭建一个简单的安全认证系统。即使你是编程新手也不用担心,我们会从头教起,手把手带你写代码!


环境准备:搭建开发环境

环境准备:搭建开发环境

在正式开始之前,我们需要准备好开发工具和相关依赖。下面是一个清晰的操作指南。

1. 安装 JDK

首先确认你已经安装了 Java 开发工具包(JDK),推荐版本为 JDK 17 或以上

如何检查:

打开命令行(Windows 是 cmd 或 PowerShell,Mac 是终端)输入:

java -version

如果你看到类似如下的信息,说明安装好了:

openjdk version "17.0.6" 2023-01-17

如果没有安装,请前往 Oracle官网 或使用像 Adoptium 这样的开源 JDK 提供商下载安装。


2. 安装 IDE(推荐 IntelliJ IDEA)

IntelliJ IDEA 是 Java 开发中最常用的集成开发环境(IDE),免费的 Community 版本就能满足我们的需求。

下载地址:https://www.jetbrains.com/idea/download/

安装完成后启动它。


3. 创建一个新的 Spring Boot 项目

打开 https://start.spring.io/,这是一个官方提供的 Spring Boot 项目生成器。

选择以下配置:

  • Project: Maven
  • Language: Java
  • Spring Boot Version: 建议选 3.x 的稳定版本
  • Group: com.example (这是项目组织名)
  • Artifact: security-demo (这是项目名)
  • Dependencies: 添加两个:
    • Spring Web
    • Spring Security

点击下方的 “Generate” 下载项目压缩包。

解压后,用 IntelliJ 打开这个文件夹即可看到初始项目结构。


4. 启动项目测试

找到 SecurityDemoApplication.java 文件,在右侧点击运行按钮或者使用快捷键运行它。

等待控制台出现如下内容表示启动成功:

Tomcat started on port(s): 8080 (http)

浏览器访问 http://localhost:8080,你会看到一个默认错误页(因为还没定义任何页面)——但这说明你的基本开发环境已经搭建完成!


核心概念:通俗理解 Spring Security 的关键知识点

API接口文档-1

在真正动手前,我们先来简单了解几个核心术语,这样在后面学习的时候不会晕菜。

1. 认证(Authentication)

简单说,就是判断一个人是谁。比如你登录微信时输入账号密码,就是在做认证。

Spring Security 中的认证过程包括:

  • 用户提交账号密码
  • 系统验证信息是否正确
  • 如果正确,就允许访问资源

2. 授权(Authorization)

授权的意思是:“虽然我知道你是谁,但你能访问哪些东西呢?”

例如:

  • 普通用户只能看主页
  • 管理员可以看到后台数据

3. 用户凭证(User Details)

就是用户的信息,通常包括用户名、密码、角色(role)等。Spring Security 中通过 UserDetailsService 来加载这些信息。

4. 过滤器链(Filter Chain)

就像一道道门卫,对每个请求进行检查。Spring Security 使用多个过滤器来做不同的安全处理。

比如:

  • 第一个过滤器负责检查是否已经登录
  • 第二个负责记录日志
  • 第三个负责防止攻击……

我们可以自定义这些过滤器来做更复杂的控制。


实战项目:一步一步构建安全系统

接下来我们将创建一个简单的 Spring Boot 应用,包含以下功能:

  • 提供一个登录页面
  • 用户登录后可以访问 /home
  • 未登录访问该页面则重定向到登录页
  • 演示管理员与普通用户的权限差异

第一步:创建简单的控制器

新建一个类 HomeController.java 放在 com.example.securitydemo.controller 包下:

package com.example.securitydemo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HomeController {
    
    @GetMapping("/")
    public String index() {
        return "欢迎来到首页!请 <a href=\"/login\">登录</a>";
    }

    @GetMapping("/home")
    public String home() {
        return "你已成功登录!这里是主页";
    }
}

现在你可以重启应用,并访问 http://localhost:8080http://localhost:8080/home 测试一下,默认都能直接访问。

接下来我们要启用 Spring Security 来限制访问。


第二步:添加 Spring Security 配置类

创建一个新的类 SecurityConfig.javacom.example.securitydemo.config 包下:

package com.example.securitydemo.config;

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.config.annotation.web.configuration.EnableWebSecurity;
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
@EnableWebSecurity
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("admin123")
                .roles("ADMIN")
                .build();
        return new InMemoryUserDetailsManager(user, admin);
    }

    // 设置 URL 访问权限规则
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/").permitAll()
                .requestMatchers("/home").authenticated()
            )
            .formLogin(login -> login
                .loginPage("/login")  // 自定义登录页路径
                .defaultSuccessUrl("/home", true)
                .permitAll()
            )
            .logout(logout -> logout.permitAll());
        
        return http.build();
    }
}

上面的代码主要做了三件事:

  1. 配置了两个内存用户:一个普通用户(user / 123456),一个管理员(admin / admin123)
  2. 设置了 URL 访问权限:首页所有人可访问,/home 只有登录用户才能访问
  3. 启用了表单登录界面(稍后我们会创建登录页面)

⚠️ 注意:这里我们为了演示方便,采用的是最简单的内存方式存储用户信息,实际项目中一般会从数据库读取用户信息。


第三步:创建登录页面

resources/templates 目录下创建一个名为 login.html 的文件(记得先创建 templates 目录):

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <h3>请登录</h3>

    <form action="/login" method="post">
        用户名:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        <input type="submit" value="登录">
    </form>

    <p th:text="${error}" style="color:red;"></p>
</body>
</html>

然后在之前的 HomeController 中添加一个方法,展示这个登录页面:

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

重启程序,再次访问:

尝试用 user / 123456 登录看看!


第四步:基于角色设置权限

刚才的例子只是实现了最基本的认证功能。我们现在升级一下:让 /admin 路径只能由 ADMIN 角色访问。

修改 SecurityConfig 类中的权限配置部分:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/").permitAll()
            .requestMatchers("/home").authenticated()
            .requestMatchers("/admin").hasRole("ADMIN")  // 新增这一行
        )
        .formLogin(login -> login
            .loginPage("/login")
            .defaultSuccessUrl("/home", true)
            .permitAll()
        )
        .logout(logout -> logout.permitAll());

    return http.build();
}

同时,在 HomeController 中增加一个新方法:

@GetMapping("/admin")
public String adminHome() {
    return "欢迎管理员!这里是私密区域";
}

重启服务后,用 admin / admin123 登录访问 /admin,再用普通用户访问,看看效果。


常见问题:新手容易踩坑的地方

1. 为什么会提示 “Bad credentials”?

这通常是用户名或密码不对。注意 Spring Security 默认要求用户名区分大小写,密码也要完全匹配。

解决办法:

  • 检查是否输入了正确的用户名和密码
  • 确保没有多余的空格
  • 检查 SecurityConfig 中的密码是否正确

2. 页面访问一直跳回登录页,怎么回事?

可能是权限配置搞错了。比如你想访问 /home,但忘记加 .authenticated()

解决办法:

  • 查看 SecurityConfig 中的路径匹配规则
  • 确保对应路径的访问权限设置正确

3. Thymeleaf 报错 Could not parse as expression

如果你在登录页面中加入了 <p th:text="${error}">,但在没有引入 Thymeleaf 插件的情况下会出错。

解决办法:

  • 暂时不加这段代码,或者
  • 添加 Thymeleaf 依赖(可以在 start.spring.io 再添加一次依赖)

4. 表单提交报错:CSRF token missing

Spring Security 默认开启 CSRF 防护,也就是防止别人偷偷发送请求。如果你自己写的登录页面没有加上 Token 验证就会出错。

解决办法:

  • 在页面中加入隐藏字段:
<input type="hidden" name="_csrf" th:value="${_csrf.token}">

或者临时关闭 CSRF(仅限练习环境):

SecurityConfig 的最后加上:

.csrf(csrf -> csrf.disable())

⚠️ 生产环境中不要禁用 CSRF!


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

恭喜你完成了第一个安全系统的基础搭建!你已经掌握了:

  • Spring Security 的基本原理
  • 用户认证和角色管理
  • 控制 URL 的访问权限
  • 简单的登录页面设计

接下来你可以继续深入学习以下几个方向:

🧪 一、实战进阶

  • 【实操】使用数据库存储用户信息(如 MySQL + Spring Data JPA)
  • 【实操】实现注册功能 + 邮箱验证码
  • 【实操】使用 JWT 做无状态身份验证(适用于前后端分离架构)

🔐 二、安全增强

  • 学习 Spring Security 中的 OAuth2 协议(支持 GitHub 登录等第三方登录)
  • 加入 RBAC(基于角色的权限管理)模型
  • 学习 CSRF、XSS 攻击防护机制

🛠 三、技术提升

  • 学习 AOP 在权限控制中的应用
  • 配合 Redis 缓存用户 session
  • 使用 Spring Security Test 做单元测试

总结

这篇文章我们从零开始搭建了一个使用 Spring Security 的安全系统,包括用户登录、权限管理、URL 控制等功能。希望你在这个过程中不仅学会了“怎么用”,也理解了“为什么这么做”。

如果你还有疑问或者想继续深入学习,欢迎留言交流。接下来我们还会分享更多关于 Spring Security 高级用法的内容,别忘了关注更新哦!


📌 附:完整代码结构概览

security-demo/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com.example.securitydemo/
│   │   │       ├── controller/
│   │   │       │   └── HomeController.java
│   │   │       ├── config/
│   │   │       │   └── SecurityConfig.java
│   │   │       └── SecurityDemoApplication.java
│   │   ├── resources/
│   │   │   ├── templates/
│   │   │   │   └── login.html
│   │   │   └── application.properties

✅ 看到这里,你已经完成了第一关!给自己点个赞吧!继续加油,成为 Spring 安全领域的高手!🚀

评论 0

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