Spring Security 从零开始:手把手教你搭建安全认证系统

一人公司实验室
2026-02-04 19:07
阅读 705

大家好,我是一个开源项目维护者,也是一名后端讲师。过去几年,我参与和维护了多个基于 Spring Boot 的企业级项目,其中几乎都离不开 Spring Security。我当初学的时候,被它的“自动配置”搞得晕头转向——明明没写代码,为什么一访问就跳登录页?用户名密码又是从哪来的?今天,我就用最简单、最实战的方式,带完全零基础的你,快速搭建一个属于自己的安全认证系统。

为什么需要 Spring Security?

想象一下,你的网站有用户注册、订单查看、后台管理等功能。如果不对访问权限做控制,任何人都能删掉别人的订单,甚至进入管理员后台,那后果不堪设想。Spring Security 就是 Spring 家族中专门用来处理“谁可以访问什么”的安全框架。它能帮你轻松实现:

  • 用户登录认证(Authentication)
  • 权限控制(Authorization)
  • 防止常见攻击(如 CSRF、会话固定等)

而我们今天的目标,就是用最少的代码,跑通一个带登录功能的 Web 应用。


第一步:环境准备

在开始之前,请确保你已经安装了以下工具:

工具 版本建议 说明
JDK 17 或 21 Spring Boot 3.x 要求 JDK 17+
Maven / Gradle 最新稳定版 项目构建工具,本文使用 Maven
IDE IntelliJ IDEA / VS Code 推荐 IDEA,对 Spring 支持更好

创建 Spring Boot 项目

  1. 打开 https://start.spring.io
  2. 选择:
    • Project: Maven
    • Language: Java
    • Spring Boot: 3.3.x(最新稳定版)
    • Group: com.example
    • Artifact: security-demo
  3. Dependencies 中添加:
    • Spring Web
    • Spring Security

点击“Generate”,下载 ZIP 文件并解压,导入到你的 IDE 中。

💡 小提示:如果你用的是 IDEA,可以直接在新建项目时选择 Spring Initializr,效果一样。


第二步:理解核心概念(用大白话讲)

在写代码前,先搞懂几个关键术语,避免后面“看天书”:

1. 认证(Authentication) vs 授权(Authorization)

  • 认证:你是谁?比如输入用户名和密码登录。
  • 授权:你能做什么?比如普通用户只能看自己订单,管理员能删所有订单。

2. SecurityFilterChain

这是 Spring Security 的“总开关”。你可以把它想象成一个安检门:

  • 所有请求进来,都要经过它检查
  • 如果没登录,直接拦下,跳转到登录页
  • 如果有权限,放行

3. UserDetailsService

这是一个接口,负责“查用户”。Spring Security 会问它:“这个用户名存在吗?密码是多少?”
你可以从数据库查,也可以像我们下面这样,临时写死几个用户用于测试。


第三步:动手写一个最简单的安全系统

现在,我们一步步来写代码。

1. 创建一个简单的首页

src/main/java/com/example/securitydemo/controller 下新建文件:

// HomeController.java
package com.example.securitydemo.controller;

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

@RestController
public class HomeController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, this is a protected page!";
    }
}

启动应用(运行 SecurityDemoApplication.java),访问 http://localhost:8080/hello —— 你会发现页面跳转到了 /login,而且浏览器提示你输入用户名密码!

这就是 Spring Security 的默认行为:所有路径都受保护,必须登录才能访问

2. 自定义用户和密码

默认情况下,Spring Security 会在启动时生成一个随机密码(打印在控制台)。但我们要自己控制。

创建一个配置类:

// SecurityConfig.java
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.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated() // 所有请求都需要认证
            )
            .formLogin(form -> form
                .loginPage("/login") // 使用默认登录页
                .permitAll()         // 登录页本身不需要认证
            )
            .logout(logout -> logout
                .permitAll()
            );
        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.builder()
            .username("user")
            .password("{noop}123456") // {noop} 表示不加密
            .roles("USER")
            .build();

        return new InMemoryUserDetailsManager(user);
    }
}

⚠️ 注意:{noop} 是告诉 Spring “密码没加密”,仅用于开发!生产环境必须用加密(如 BCrypt)。

重启应用,再次访问 http://localhost:8080/hello,会看到登录页。输入:

  • 用户名:user
  • 密码:123456

就能看到 “Hello, this is a protected page!” 了!

3. 添加一个公开页面

有些页面(比如首页、注册页)不需要登录。我们来加一个:

// PublicController.java
@GetMapping("/welcome")
public String welcome() {
    return "Welcome to our site! No login required.";
}

然后修改 SecurityConfig 中的 authorizeHttpRequests

.authorizeHttpRequests(auth -> auth
    .requestMatchers("/welcome").permitAll() // 允许所有人访问
    .anyRequest().authenticated()
)

现在,访问 http://localhost:8080/welcome 不需要登录,而 /hello 仍需要。


第四步:常见问题与避坑指南

❓ 问题1:为什么我的密码总是错?

  • 检查是否用了 {noop}。如果你写的是 .password("123456"),Spring 会认为这是加密后的密码,而实际你输入的是明文,所以永远不匹配。
  • 正确写法:.password("{noop}123456")

❓ 问题2:登录页样式太丑,能改吗?

当然可以!Spring Security 默认提供了一个极简登录页。你可以自定义 HTML 页面,只需在 formLogin() 中指定:

.formLogin(form -> form
    .loginPage("/my-login") // 指向你的自定义页面
)

然后创建一个 Controller 返回该页面即可。

❓ 问题3:如何从数据库读取用户?

InMemoryUserDetailsManager 换成你自己的 UserDetailsService 实现:

@Service
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) {
        // 从数据库查询用户
        UserEntity user = userRepository.findByUsername(username);
        if (user == null) throw new UsernameNotFoundException("...");
        return User.builder()
            .username(user.getUsername())
            .password(user.getPassword()) // 注意:这里应是加密后的密码
            .roles("USER")
            .build();
    }
}

并在 SecurityConfig 中注入它:

@Bean
public UserDetailsService userDetailsService() {
    return new MyUserDetailsService(); // 或直接 @Autowired 注入
}

第五步:进阶思考:Fine-tuning 与 DeepSeek

你可能注意到文章标题提到了 DeepSeekFine-tuning。这看起来和 Spring Security 无关?其实不然。

在实际开发中,安全策略往往需要“微调”(Fine-tuning)。比如:

  • 不同角色访问不同 API
  • JWT 令牌替代 Session
  • 集成 OAuth2(如微信登录)

DeepSeek 这类 AI 编程助手,正可以帮助你快速生成这些复杂配置的模板。例如,你可以问:

“用 Spring Security 3.3 实现基于 JWT 的无状态认证,返回完整代码”

AI 会给你一个结构清晰的起点,你再根据业务需求 Fine-tune(微调) 细节。这比从零查阅文档快得多。

但记住:AI 是助手,不是替代品。理解底层原理(比如 FilterChain 的执行顺序),才能在出问题时快速定位。


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

恭喜你,已经迈出了安全开发的第一步!接下来,我建议你按这个顺序深入:

  1. 密码加密:学习 BCryptPasswordEncoder,替换 {noop}
  2. 角色与权限:尝试 hasRole('ADMIN')hasAuthority('DELETE_ORDER')
  3. JWT 集成:实现无状态认证,适合前后端分离项目
  4. OAuth2 / OIDC:集成第三方登录(微信、GitHub)
  5. 安全最佳实践:CSRF 防护、CORS 配置、安全头设置

📌 我的建议:不要试图一次学完所有功能。先用内存用户跑通流程,再逐步替换为数据库、加密、JWT 等模块。


结语

我当初学 Spring Security 时,也被它的“魔法”吓到过。但只要你理解了 FilterChain 是入口,UserDetailsService 是用户来源,剩下的就是配置问题。今天这个教程,就是我当年希望有人能给我的“最小可行示例”。

安全不是功能,而是底线。花一点时间掌握 Spring Security,能让你的项目从第一天就远离很多低级漏洞。

现在,去你的项目里加一行 .authorizeHttpRequests(...) 吧!你已经比昨天的自己更安全了。

Happy Coding!

评论 0

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