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

极客小岛
2025-06-15 23:03
阅读 302

开篇:为什么我们需要Spring Security?

开篇:为什么我们需要Spring Security?

你有没有想过,当你在某个网站登录账号的时候,后台是怎么知道你是谁,并且只让你看到属于你的数据呢?
这就是“安全认证”在起作用。而Spring Security就是Java世界中,用来帮助我们实现这种功能的利器。

简单来说,Spring Security 是一个基于 Java 的安全框架,它的核心任务是:

  • 控制谁能访问我们的网站或 API
  • 验证用户身份(也就是登录验证)
  • 授权用户权限(比如管理员能干啥、普通用户只能看不能改)

这篇文章会带你从零开始,用最简单的例子一步步搭建出一个有登录功能的安全系统。即使你完全没有接触过 Spring Security,也能轻松上手。


环境准备:你需要哪些工具?

环境准备:你需要哪些工具?

开始之前,先准备好以下开发环境:

1. 安装 JDK(Java Development Kit)

推荐使用 JDK 8 或以上版本。可以到 Oracle官网 或者使用 OpenJDK 发行版如 Azul Zulu 下载安装。

检查是否安装成功,打开命令行输入:

java -version

输出类似如下内容表示安装成功:

openjdk version "17.0.3" 2022-04-19
OpenJDK Runtime Environment ...

2. 安装 IDE(集成开发环境)

推荐使用 IntelliJ IDEA(社区版即可)或者 Eclipse。


3. 安装 Spring Boot 项目生成器

我们使用 Spring Initializr 来创建项目骨架。

创建步骤:

  1. 打开浏览器访问 https://start.spring.io/

  2. 选择配置如下:

    • Project: Maven
    • Language: Java
    • Spring Boot Version: 例如 3.0.x 或最新稳定版
    • Group: com.example
    • Artifact: spring-security-demo
    • Name: spring-security-demo
    • Description: Demo project for Spring Security
    • Packaging: Jar
    • Java: 17
  3. 添加依赖(按住 Ctrl 多选):

    • Spring Web (用于构建 web 应用)
    • Spring Security
  4. 点击 Generate 按钮下载项目压缩包,解压后导入 IDE。

这样我们就有了一个带 Spring Security 支持的基本项目模板。


核心概念解释:理解几个关键词

对于初学者来说,下面这几个词经常出现,但含义可能不太清楚。我们来用通俗的方式解释一下:

1. 认证(Authentication)

想象你在机场安检口,工作人员要查你的身份证。
这就是“认证”——确认你是谁的过程。对应的是“登录”操作。

2. 授权(Authorization)

确认完你是谁之后,工作人员告诉你只能去国内候机厅,不能进VIP休息室。
这就是“授权”——确认你能做什么事情

3. 过滤器(Filter)

你可以把它理解成一扇门,所有请求都要经过它,根据规则放行或拦截。

比如:

  • 非法请求直接拒绝
  • 匿名用户只能访问首页
  • 登录用户才能访问管理页面

Spring Security 就是一系列这样的“过滤器链”。


4. UserDetailsService

这是一个接口,用来告诉 Spring Security:“我系统里的用户是从哪儿来的?”
你可以从数据库、文件甚至内存中读取用户信息。


实战项目:搭建一个基础认证系统

接下来我们通过动手写代码,来实际体验 Spring Security 的基本用法。

Step 1:启用 Spring Security

新建一个 Spring Boot 启动类,如果你使用 Spring Initializr 生成的项目,这个类已经自动生成了。

package com.example.springscuritydemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringSecurityDemoApplication {

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

}

启动后,默认情况下,Spring Security 已经为整个应用开启了保护机制。你可以运行程序后访问任意接口,会被自动跳转到登录页。

但此时还没有我们自己的登录逻辑,所以需要进一步配置。


Step 2:添加安全配置类

新建一个类:SecurityConfig.java

package com.example.springscuritydemo.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.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 userDetailsManager() {
        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);
    }

    // 安全过滤链配置
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(login -> login
                .loginPage("/login")     // 自定义登录页
                .permitAll()
            )
            .logout(logout -> logout
                .permitAll()
            );

        return http.build();
    }
}

这段代码做了几件重要的事情:

  1. 使用 InMemoryUserDetailsManager 定义了两个用户:一个是普通用户,一个是管理员。
  2. 对不同的 URL 进行访问控制:
    • / 允许任何人访问(无需登录)
    • /admin/** 只有 ADMIN 角色的用户可以访问
    • 其他路径必须登录才能访问
  3. 启用了默认的表单登录界面,并允许所有人访问 /login 页面
  4. 启用了注销功能(默认地址 /logout

⚠️ 注意:这里使用的是内存用户存储方式,仅适合测试使用。真实项目应连接数据库或其他用户源。


Step 3:添加控制器(Controller)

接下来我们编写两个控制器方法,模拟普通页面和受保护页面。

新建 HomeController.java

package com.example.springscuritydemo.controller;

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

@Controller
public class HomeController {

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

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

Step 4:添加HTML页面(Thymeleaf)

由于我们没有引入前端框架,使用 Thymeleaf 模板引擎来展示页面。

src/main/resources/templates/ 目录下创建:

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>欢迎来到首页!</h1>
<p><a href="/admin/dashboard">进入管理后台</a></p>
</body>
</html>

admin/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>管理员页面</title>
</head>
<body>
<h1>管理员后台</h1>
<p>只有登录后的管理员才能看到的内容。</p>
<a href="/logout">退出登录</a>
</body>
</html>

Step 5:测试运行!

启动 Spring Boot 应用:

mvn spring-boot:run

访问 http://localhost:8080,你会看到:

  • 第一次访问会自动跳转到登录页面
  • 输入用户名和密码(比如:user / 123456),点击登录
  • 成功后可以访问首页
  • 如果你是普通用户,点击“进入管理后台”时会被拒绝访问
  • 管理员账户(admin/admin123)则可以访问管理页面

常见问题解答

❓ Q1:为什么我输入正确用户名密码却登录失败?

  • 检查用户名和密码是否准确(注意大小写)
  • 看是否设置了角色匹配(比如访问 /admin 需要有 ADMIN 角色)
  • 查看控制台是否有报错日志,如“Bad credentials”

解决办法:

  • 使用 .withDefaultPasswordEncoder() 保证密码正确加密
  • 使用 debug 日志查看详细过程:logging.level.org.springframework.security=DEBUG

❓ Q2:如何自定义登录页面?

修改 SecurityConfig 中的 .loginPage("/login") 并新增一个 controller 方法指向你的 HTML 页面即可。

示例:

@GetMapping("/login")
public String login() {
    return "custom-login";  // 返回自定义登录页面
}

然后在 templates 文件夹下创建 custom-login.html


❓ Q3:如何让某些资源不需要登录就能访问?

比如静态资源、API文档等。

可以在 SecurityFilterChain 中使用 .permitAll(),例如:

.authorizeRequests()
    .requestMatchers("/css/**", "/js/**", "/favicon.ico").permitAll()
    .anyRequest().authenticated()

❓ Q4:为什么登出后还能访问受保护资源?

可能是浏览器缓存了 Cookie。尝试清除浏览器缓存或者使用无痕窗口测试。


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

你现在掌握了一个最基础的安全系统搭建流程。接下来你可以沿着以下几个方向继续深入学习:

✅ 深入方向一:数据库认证

将用户信息从内存改为从数据库加载,比如 MySQL + JPA。

关键点:

  • 实现 UserDetailsService 接口
  • 编写数据库实体和 Repository
  • 配置 BCryptPasswordEncoder 加密密码

✅ 深入方向二:OAuth2 和 JWT

随着现代应用的发展,传统的 Session 认证已经不够灵活。了解 OAuth2 协议和 JWT 令牌技术,将使你能够构建更高级的身份验证系统。

推荐阅读:


✅ 深入方向三:权限细粒度控制

当前我们只是按角色控制访问。在实际开发中,可能还需要基于具体权限进行控制,例如:

  • 用户A有“订单查看”权限
  • 用户B有“订单编辑”权限

可以通过 Spring Security 的 @PreAuthorize 注解配合 SpEL 表达式实现精细权限判断。

示例:

@PreAuthorize("hasAuthority('EDIT_ORDERS')")
public void editOrder(Order order) { ... }

结语:不要怕,安全其实很有趣!

数据流转过程-1

刚开始学习 Spring Security 时,可能会觉得配置复杂、术语多。但只要你从实践中入手,逐步尝试每个小功能,慢慢你会发现:

✅ 它结构清晰
✅ 功能强大
✅ 可扩展性极高

希望这篇教程能帮你迈出安全认证的第一步。别忘了边看边动手,把每一个知识点都落实到代码中,效果才最好。

祝你越学越顺利!


作者:一位热爱教学的后端讲师

评论 0

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