Spring Security零基础入门:5分钟搭起你的第一个安全系统

架构还没想好
2025-12-23 08:32
阅读 1083

大家好,我是工作5年的后端开发工程师。记得我当初学Spring Security的时候,光是看文档就花了整整两天,配置完还各种报错——登录页跳转不了、密码加密方式不对、权限死活不生效……真的头大。

所以今天,我想用最简单的方式,带你快速上手Spring Security。不用懂OAuth2,不用会JWT,只要你会写Hello World,就能跟着这篇教程跑通一个带用户名密码登录的安全系统。

这篇文章就是一份“防踩坑”指南,专为Java零基础或刚接触安全认证的新手准备。我们一步步来,保证你学得明白、跑得起来!


为什么需要Spring Security?

想象一下:你做了一个后台管理系统,任何人都能直接访问 /admin 页面删数据?这显然不行。

Spring Security 就是给你的Java应用加“门锁”的工具。
它能帮你实现:

  • 用户登录(谁可以进来?)
  • 权限控制(进来后能干什么?)
  • 防止攻击(比如暴力破解、跨站请求伪造等)

而这一切,Spring Boot + Spring Security 几乎“开箱即用”。


环境准备:5分钟搭好开发环境

✅ 前提:你已经安装了 JDK 8+ 和 Maven(或 Gradle)

第一步:创建Spring Boot项目

你可以用 https://start.spring.io 快速生成项目。

依赖选择:

  • Spring Web
  • Spring Security
  • Thymeleaf(用于简单页面展示,可选但推荐)

或者直接在 pom.xml 中添加:

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

第二步:确认主启动类

确保你有类似这样的主类:

@SpringBootApplication
public class SecurityDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SecurityDemoApplication.class, args);
    }
}

搞定!环境就绪。


核心概念:3个词搞懂Spring Security

别被术语吓到,其实就三件事:

概念 通俗解释 对应代码角色
认证(Authentication) “你是谁?” —— 登录验证身份 UserDetails, UserDetailsService
授权(Authorization) “你能干啥?” —— 控制访问权限 @PreAuthorize, hasRole()
资源(Resource) 被保护的东西,比如 /api/users/admin 页面 URL路径、方法、数据库记录等

💡 重点理解“资源”:在安全系统中,任何需要保护的内容都叫“资源”。比如:

  • 一个网页(/dashboard
  • 一个API接口(/api/deleteUser
  • 甚至是一条数据库记录(“只有作者能编辑自己的文章”)

我们今天的目标:保护几个资源,只让登录用户访问。


实战:手把手搭建一个安全登录系统

我们将完成以下功能:

  1. 访问 / 显示欢迎页(无需登录)
  2. 访问 /user 需要登录
  3. 提供一个简单的登录页
  4. 使用内存中的用户账号(用户名/密码)

第一步:创建首页和用户页

src/main/resources/templates 下创建两个Thymeleaf页面:

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>首页</title></head>
<body>
  <h1>欢迎来到首页!</h1>
  <p>这是公开资源,所有人都能看。</p>
  <a th:href="@{/user}">去用户页面(需登录)</a>
</body>
</html>

user.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>用户页</title></head>
<body>
  <h1>你好,[[${#httpServletRequest.remoteUser}]]!</h1>
  <p>这是受保护的资源,只有登录用户才能看到。</p>
  <form th:action="@{/logout}" method="post">
    <button type="submit">退出登录</button>
  </form>
</body>
</html>

第二步:编写控制器

@Controller
public class PageController {

    @GetMapping("/")
    public String home() {
        return "index"; // 返回 templates/index.html
    }

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

第三步:配置Spring Security(关键!)

创建配置类:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", "/login").permitAll() // 允许所有人访问首页和登录页
                .anyRequest().authenticated()               // 其他所有请求必须登录
            )
            .formLogin(form -> form
                .loginPage("/login")       // 自定义登录页(Spring Security会自动生成)
                .permitAll()
            )
            .logout(logout -> logout
                .permitAll()
            );
        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        // 创建一个内存中的用户:用户名 user,密码 123456
        UserDetails user = User.builder()
            .username("user")
            .password(passwordEncoder().encode("123456"))
            .roles("USER")
            .build();

        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 密码必须加密存储!
    }
}

🔒 重要提醒:Spring Security 强制要求密码加密!如果你直接写 .password("123456"),启动会报错。所以我们用 BCryptPasswordEncoder 加密。

第四步:运行并测试

  1. 启动应用(默认端口8080)
  2. 访问 http://localhost:8080 → 看到首页
  3. 点击链接进入 /user → 自动跳转到 /login
  4. 输入用户名 user,密码 123456 → 成功进入用户页
  5. 点击“退出登录” → 回到登录页

🎉 恭喜!你已经搭建了一个完整的认证系统!


新手常见问题 & 解决方案

❓ 问题1:为什么登录页是Spring Security自动生成的?我能自定义吗?

:当然可以!上面我们用了 .loginPage("/login"),但没提供 /login 的页面,所以Spring Security自动渲染了一个默认登录页。

如果你想自定义,只需加一个控制器:

@GetMapping("/login")
public String login() {
    return "login"; // 你需要自己写 login.html
}

然后在 login.html 中包含表单(注意字段名必须是 usernamepassword):

<form th:action="@{/login}" method="post">
  <input type="text" name="username" placeholder="用户名" />
  <input type="password" name="password" placeholder="密码" />
  <button type="submit">登录</button>
</form>

❓ 问题2:密码明文写在代码里不安全,怎么办?

:这只是教学示例!实际项目中,用户数据应来自数据库。

你可以这样改:

  1. 创建 UserRepository 查询数据库
  2. 实现 UserDetailsService 接口,从DB加载用户
  3. 依然使用 BCryptPasswordEncoder 加密比对

后续我会专门写一篇《Spring Security + 数据库实战》。

❓ 问题3:如何区分“普通用户”和“管理员”?

:用角色(Role)!比如:

User admin = User.builder()
    .username("admin")
    .password(encoder.encode("admin123"))
    .roles("ADMIN") // 注意:这里会自动加前缀 ROLE_
    .build();

然后在配置中限制:

.requestMatchers("/admin/**").hasRole("ADMIN") // 只有ROLE_ADMIN能访问

💡 Spring Security 会自动给角色加 ROLE_ 前缀,所以 .roles("ADMIN") 实际存储为 ROLE_ADMIN


学习建议:下一步怎么走?

你现在已经掌握了Spring Security的基础骨架。接下来可以按这个路径深入:

  1. 连接真实数据库
    InMemoryUserDetailsManager 换成从MySQL/PostgreSQL读取用户。

  2. 理解过滤器链(Filter Chain)
    Spring Security底层是一堆过滤器,了解它们有助于调试。

  3. 尝试前后端分离方案
    用 JWT 或 Session + Cookie 实现 API 认证(适合Vue/React前端)。

  4. 学习方法级安全
    @PreAuthorize("hasRole('ADMIN')") 保护Service方法。

  5. 集成第三方登录
    如微信、GitHub、Google登录(需要用到OAuth2)。

📌 避坑指南

  • 不要关闭CSRF防护(除非做纯API且用Token)
  • 永远不要明文存密码
  • 开发时可用 .csrf().disable() 临时关闭CSRF,但上线务必开启!

结语

这篇【Spring Security基础:快速搭建安全认证系统】的教程,就是我当年希望有人能给我的那份“救命文档”。它没有讲原理堆砌,而是聚焦于“让你立刻跑起来”。

记住:安全不是功能,而是基础设施。哪怕你的项目再小,也应该从第一天就考虑“谁可以访问什么资源”。

现在,打开你的IDE,照着代码敲一遍吧!遇到问题,欢迎留言讨论。下期我们讲《Spring Security + MySQL:从内存用户到数据库认证》。

祝你编码愉快,安全无忧!

评论 0

最热最新
暂无评论
架构还没想好Lv.1
0
影响力
0
文章
0
粉丝