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

锦上添花
2025-06-15 11:19
阅读 415

开篇:Spring Security是什么?它能帮我们做什么?

开篇:Spring Security是什么?它能帮我们做什么?

如果你是一名Java开发者,或者刚开始学习后端开发,你可能会遇到这样一个问题:用户登录、权限控制这些功能在每个项目中都要写一遍,太麻烦了!这时候,Spring Security 就派上用场了。

简单来说,Spring Security 是一个为基于 Spring 的应用程序提供安全服务的安全框架。它可以帮你轻松实现以下功能:

  • 用户登录(认证)
  • 权限控制(授权)
  • 防止常见的安全漏洞(如CSRF、XSS攻击)
  • 多种认证方式支持(用户名密码、OAuth、JWT等)

它的设计非常灵活,你可以根据需求定制各种安全规则。本教程将从零开始,手把手教你如何使用 Spring Security 搭建一个简单的用户登录和权限管理的小项目。


环境准备:搭建开发环境

环境准备:搭建开发环境

在正式学习之前,我们需要准备好开发环境。

1. 安装JDK

确保你安装了 Java Development Kit(JDK),推荐使用 JDK 8 及以上版本。

如何查看是否已安装 JDK?

打开命令行,输入:

java -version

如果看到类似 openjdk version "11.0.2" 这样的信息,说明你已经安装好了。

2. 安装IDE

推荐使用 IntelliJ IDEAEclipse。如果你是新手,建议使用 IntelliJ IDEA 社区版,界面友好,智能提示丰富。

3. 创建Spring Boot项目

我们可以直接通过 https://start.spring.io 快速生成一个 Spring Boot 项目。

步骤如下:

  1. 访问 https://start.spring.io
  2. 选择如下配置:
    • Project: Maven
    • Language: Java
    • Spring Boot Version: 最新稳定版(比如 3.1.x)
    • Project Metadata:
      • Group: com.example
      • Artifact: securitydemo
      • Name: securitydemo
      • Description: Spring Security Demo
      • Package name: com.example.securitydemo
  3. Dependencies: 添加以下两个依赖
    • Spring Web
    • Spring Security
  4. 点击 “Generate” 下载项目压缩包

解压项目后,用IDE导入即可。


核心概念:Spring Security的几个关键角色和流程

核心概念:Spring Security的几个关键角色和流程

虽然我们还没写代码,但了解一些基本术语会让你更容易理解后续内容。

1. 用户认证(Authentication)

通俗点说就是“验证你是谁”。比如:你在网站上输入用户名和密码进行登录,服务器会检查你的账号是否存在,密码是否正确。

2. 授权(Authorization)

这是指“你能干什么”。比如管理员可以发布文章,普通用户只能查看。

3. 用户(User)、角色(Role)、权限(Authority)

这三者的关系就像这样:

名称 解释 示例
User 操作系统的使用者 张三、李四
Role 用户的身份 ROLE_USER, ROLE_ADMIN
Authority 更细粒度的操作权限 READ_PRIVILEGE, WRITE_PRIVILEGE

一个用户可以有多个角色,一个角色又可以拥有多项权限。

4. Filter(过滤器)和认证流程

Spring Security 是基于过滤器链(Filter Chain)来实现安全控制的。

你可以把 Filter 想象成安检门,每一个请求都要经过一系列“门禁”,每一扇门都会做不同的判断。比如登录认证、权限检查、防止 CSRF 攻击等等。

我们目前只需要知道这一点就可以了,后面实战时再详细讲。


实战项目:一步步完成一个安全认证系统

服务器部署方案-1

现在进入正题:动手写一个带有登录功能和权限控制的小项目

我们将构建一个简单的 Web 应用,包含以下几个功能:

  • 用户登录页面
  • 登录成功后访问主页
  • 不同用户拥有不同权限,访问受限资源

第一步:创建Spring Boot项目结构

我们前面已经下载好了项目,打开之后目录结构如下:

├── pom.xml
├── src
│   └── main
│       ├── java
│       │   └── com.example.securitydemo
│       │       ├── SecuritydemoApplication.java
│       └── resources
│           └── application.properties

第二步:添加基本页面和控制器

我们先不涉及数据库,先在内存中配置用户信息。

1. 创建Controller

com.example.securitydemo 包下新建一个类 HomeController.java

package com.example.securitydemo;

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

@Controller
public class HomeController {

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

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

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

这个控制器定义了三个页面:

  • /: 主页
  • /admin: 只有管理员才能访问
  • /login: 自定义登录页面

2. 创建Thymeleaf模板文件

src/main/resources/templates/ 目录下创建三个HTML文件:

home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>主页</title>
</head>
<body>
<h1>欢迎来到首页</h1>
<a th:href="@{/admin}">进入管理员页面</a><br/>
<a th:href="@{/logout}">退出登录</a>
</body>
</html>
admin.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>管理员页面</title>
</head>
<body>
<h1>管理员专用页面</h1>
<p>只有管理员能看到哦!</p>
<a th:href="@{/}">返回主页</a>
</body>
</html>
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>登录页面</title>
</head>
<body>
<h2>请登录</h2>

<form method="post" action="/login">
    <div>
        <label>用户名:</label>
        <input type="text" name="username" />
    </div>
    <div>
        <label>密码:</label>
        <input type="password" name="password" />
    </div>
    <button type="submit">登录</button>
</form>
</body>
</html>

3. 在 application.properties 中启用Thymeleaf

spring.thymeleaf.cache=false

为了方便调试,关闭缓存。


第三步:配置Spring Security

接下来我们要告诉 Spring Security:

  • 哪些页面需要认证
  • 用户名密码放在哪里(内存 or 数据库)
  • 怎么跳转到登录页面

com.example.securitydemo 包下新建一个类 SecurityConfig.java

package com.example.securitydemo;

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 {

    // 配置用户信息:两个用户,user 和 admin
    @Bean
    public UserDetailsService 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("/", "/login").permitAll()
                .requestMatchers("/admin").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin((login) -> login
                .loginPage("/login")
                .defaultSuccessUrl("/")  // 登录成功跳转地址
                .permitAll()
            )
            .logout((logout) -> logout
                .logoutSuccessUrl("/")  // 退出登录后的跳转页面
                .permitAll()
            );
        return http.build();
    }
}

⚠️ 注意:

withDefaultPasswordEncoder() 是为了演示方便使用的弱密码编码方式,在生产环境中应该使用更强的加密算法如 BCryptPasswordEncoder


第四步:运行项目并测试

启动应用:

./mvnw spring-boot:run

访问 http://localhost:8080

  • 点击“进入管理员页面”会被拦截,并跳转到 /login
  • 输入用户名和密码:
    • 用户:user / 密码:123456
    • 管理员:admin / 密码:123456
  • 登录后可以看到主页,admin用户能看到管理员页面,user用户无法访问

✅ 至此,你已经完成了一个最基础的 Spring Security 安全系统!


常见问题解答:新手常见疑问汇总

Q1:为什么我输入正确的用户名和密码也无法登录?

A1:请检查是否开启了 CSRF(跨站请求伪造)保护,默认情况下 Spring Security 会开启该功能,如果提交表单不带 _csrf 字段就会失败。可以通过临时禁用 CSRF 来测试,添加以下配置:

.httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.disable()) // 测试期间禁用

不过切记不要在生产环境中关闭 CSRF 保护!


Q2:能不能设置多个角色访问同一个资源?

A2:当然可以,例如:

.authorizeHttpRequests(auth -> auth
    .requestMatchers("/admin").hasAnyRole("ADMIN", "MODERATOR")
    ...
)

Q3:我怎么查看当前用户的用户名?

可以在 Thymeleaf 页面中使用如下方式显示用户名:

<div sec:authorize="isAuthenticated()">
  欢迎你,<span sec:authentication="principal.username"></span>
</div>

还需要引入 Thymeleaf Security 依赖:

<!-- 在 pom.xml 中添加 -->
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>

注意:Spring Boot 版本决定 Spring Security 版本,对应依赖的数字也要调整(如上面是 6)。


Q4:Spring Security 默认密码加密方式有哪些?怎么选?

A4:常用的加密方式有:

  • NoOpPasswordEncoder: 不加密(不推荐)
  • BCryptPasswordEncoder: 强烈推荐,在保存密码时自动加盐处理
  • SCryptPasswordEncoder, Argon2PasswordEncoder 等现代算法也可使用

示例代码:

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

然后修改用户配置部分:

UserDetails user = User.builder()
        .username("user")
        .password(passwordEncoder().encode("123456"))
        .roles("USER")
        .build();

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

你现在掌握的是 Spring Security 的入门级知识。接下来可以从以下几个方向继续深入:

方向一:整合数据库做真实用户系统

目前我们用了内存中的用户数据,实际中应连接 MySQL、PostgreSQL、MongoDB 等数据库。可以尝试自定义 UserDetailsService 接口,结合 JPA 查询数据库用户信息。

方向二:使用 JWT Token 实现无状态认证

传统 Session 认证适合小型网站,但在分布式架构或移动端中更常用 JWT(JSON Web Token)。Spring Security 提供扩展接口支持。

方向三:集成 OAuth2.0 登录系统

很多应用都提供“微信登录”、“QQ登录”等功能,背后就是 OAuth2 协议。你可以试试集成 Spring Security OAuth2 Client 模块。

方向四:前后端分离 + CORS 设置

如果是前后端分离项目(如 Vue + Spring Boot),你需要配置 CORS 并允许 Cookie 传递,这部分也属于 Spring Security 的重要内容。


结语:Spring Security 并不难,关键是实践!

这篇教程只是一个开始。Spring Security 是一个庞大而强大的工具,学会它不仅能够帮助你写出更安全的系统,也会让你在工作中更有竞争力。

记住一句话:“安全不是可选项,而是必须项”。

希望你能坚持动手敲代码,不断练习和完善自己的理解!

祝你学习顺利!🚀

评论 0

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