从零开始,用 Spring Security 给你的网站加把锁

代码温度计
2025-12-21 02:59
阅读 375

大家好!我是一个从中文系“叛逃”到程序员队伍的文科生。当初学编程时,看到“安全认证”“权限控制”这些词,总觉得高深莫测,像天书一样。后来硬着头皮啃文档、翻书籍、敲代码,才发现——其实没那么可怕!

今天我就用最直白的话,手把手带你用 Spring BootSpring Security 搭建一个最基础的安全登录系统。哪怕你连“后端”是干啥的还不太清楚,也没关系。这篇文章就是为完全零基础的朋友准备的。


为什么我们需要 Spring Security?

想象一下:你开了个会员制咖啡馆,门口得有个人检查顾客有没有会员卡。没卡的人不能进,有卡的人才能点单。

在 Web 应用里,这个“看门人”就是 Spring Security。它负责:

  • 谁能访问你的网页?(比如只有管理员能进后台)
  • 用户怎么证明自己是谁?(通常是输入用户名和密码)
  • 登录之后怎么记住用户?(别让用户每点一次页面就重新登录)

Spring Boot 就像一个“快速搭建工具箱”,让我们不用从零造轮子,几行配置就能跑起一个带安全功能的网站。

📚 我当初就是靠《Spring实战》这本书入门的,强烈推荐给想深入学习的朋友!


第一步:准备好你的开发环境

别担心,你不需要成为电脑专家。只要按下面几步操作就行:

你需要安装:

  1. JDK 17 或更高版本(Java 开发工具包)

  2. 一个 IDE(集成开发环境)

  3. Maven 或 Gradle(项目构建工具)

    • Spring Boot 默认用 Maven,IDEA 会自动帮你处理,不用单独装

创建项目(两种方式)

方式一:用 Spring Initializr(推荐新手)

  1. 打开浏览器,访问 https://start.spring.io
  2. 填写如下信息:
    • Project: Maven
    • Language: Java
    • Spring Boot: 选最新稳定版(比如 3.2.x)
    • Group: com.example
    • Artifact: security-demo
  3. Dependencies 搜索框里输入并添加:
    • Spring Web
    • Spring Security
  4. 点击 Generate,下载 ZIP 文件
  5. 解压后用 IDEA 打开文件夹

方式二:用 IDEA 内置创建

  • 打开 IDEA → New Project → Spring Initializr
  • 同样选择 Web 和 Security 依赖即可

💡 小贴士:我当初第一次创建项目时,漏选了 Security 依赖,结果死活找不到登录页面……所以一定要确认勾选了 Spring Security


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

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

1. 认证(Authentication)—— “你是谁?”

  • 用户输入用户名和密码
  • 系统验证是否正确
  • 正确 → 登录成功;错误 → 提示“账号或密码错误”

2. 授权(Authorization)—— “你能干什么?”

  • 比如普通用户只能看自己的订单
  • 管理员才能删除商品
  • 这叫“基于角色的权限控制”

3. 安全上下文(Security Context)—— “记住你是谁”

  • 登录后,系统会把你的身份信息存起来
  • 你访问其他页面时,不用重复登录
  • 通常通过 Cookie 或 Token 实现

✅ 重点:Spring Security 默认会自动保护所有路径!也就是说,只要你引入了它,访问 / 都会跳转到登录页。


第三步:动手写代码!搭建一个最简登录系统

现在我们来实现一个超简单的例子:访问首页需要登录,登录后显示欢迎语。

1. 看看项目结构

你的项目应该长这样:

security-demo/
├── src/main/java/com/example/securitydemo/
│   └── SecurityDemoApplication.java
├── pom.xml

2. 启动看看默认效果

直接运行 SecurityDemoApplication.java 的 main 方法。

然后打开浏览器,访问 http://localhost:8080

你会发现:

  • 页面自动跳转到 /login
  • 出现一个丑但能用的登录框
  • 用户名默认是 user
  • 密码在启动日志里!找这行:
    Using generated security password: a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8
    

🔒 这就是 Spring Security 的“默认安全策略”:自动生成一个用户,强制所有请求必须登录。

3. 自定义用户名和密码(告别随机密码)

我们当然不想每次看日志找密码。来改一下!

src/main/resources/application.properties 文件中添加:

spring.security.user.name=admin
spring.security.user.password=123456

重启应用,现在就可以用:

  • 用户名:admin
  • 密码:123456

登录试试!

4. 创建一个简单的首页

新建一个 Controller:

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

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

@Controller
public class HomeController {

    @GetMapping("/")
    @ResponseBody
    public String home() {
        return "欢迎来到我的安全网站!你已成功登录。";
    }
}

重启后访问 http://localhost:8080,登录成功就能看到这句话。

🎯 注意:@ResponseBody 表示直接返回文本,而不是跳转页面。简单演示用。


第四步:稍微进阶——配置谁可以访问什么

现在所有人都用同一个账号登录,不太现实。我们来模拟两个角色:普通用户管理员

1. 自定义用户信息(内存中存储)

⚠️ 注意:这只是教学演示!真实项目要用数据库。

创建一个配置类:

// src/main/java/com/example/securitydemo/config/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.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
public class SecurityConfig {

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

        UserDetails admin = User.builder()
                .username("admin")
                .password("{noop}456")
                .roles("ADMIN", "USER")
                .build();

        return new InMemoryUserDetailsManager(user, admin);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin/**").hasRole("ADMIN")     // /admin 开头的路径只允许 ADMIN
                .requestMatchers("/user/**").hasRole("USER")       // /user 开头的路径 USER 可访问
                .anyRequest().authenticated()                      // 其他所有路径,只要登录就行
            )
            .formLogin(form -> form
                .loginPage("/login")      // 使用默认登录页(Spring Security 自动生成)
                .permitAll()              // 登录页本身不需要认证
            )
            .logout(logout -> logout
                .permitAll()              // 注销功能对所有人开放
            );

        return http.build();
    }
}

2. 添加对应的页面接口

再加两个 Controller 方法:

@GetMapping("/user/profile")
@ResponseBody
public String userProfile() {
    return "这是普通用户的个人页面";
}

@GetMapping("/admin/dashboard")
@ResponseBody
public String adminDashboard() {
    return "这是管理员的后台面板";
}

3. 测试权限控制

  • user / 123 登录:

    • 访问 /user/profile ✅ 成功
    • 访问 /admin/dashboard ❌ 返回 403 Forbidden
  • admin / 456 登录:

    • 两个页面都能访问 ✅

🔑 关键点:

  • .hasRole("ADMIN") 会自动加上 ROLE_ 前缀,所以你在创建用户时写 roles("ADMIN") 实际存储的是 ROLE_ADMIN
  • {noop} 是告诉 Spring “密码没加密”,生产环境绝对不能这么用

新手常见问题 & 避坑指南

❓ 问题1:为什么我的登录页样式很丑?

Spring Security 默认提供的是基础 HTML 表单。你可以:

  • 自定义登录页(设置 .loginPage("/my-login") 并提供对应页面)
  • 或者集成 Thymeleaf、Vue 等前端框架美化

❓ 问题2:密码明文存储太危险了!

你说得对!真实项目必须加密。Spring Security 推荐用 BCryptPasswordEncoder

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

然后存密码时要加密:

String encodedPassword = passwordEncoder.encode("123456");
User.builder().password(encodedPassword)... 

📖 建议阅读《Spring Security in Action》这本书,讲得很细。

❓ 问题3:每次重启密码又变了?

因为你还在用默认配置!一旦你写了 SecurityConfig 并定义了 UserDetailsService,就不会再生成随机密码了。

❓ 问题4:如何获取当前登录用户信息?

在 Controller 中注入 Authentication 对象:

@GetMapping("/me")
@ResponseBody
public String getCurrentUser(Authentication auth) {
    return "当前用户: " + auth.getName();
}

下一步该学什么?

恭喜你!已经迈出了安全开发的第一步。接下来建议:

  1. 学习密码加密:掌握 PasswordEncoder 的使用
  2. 连接数据库:用 JPA 或 MyBatis 从数据库读取用户
  3. 了解 JWT:为前后端分离项目做准备(比如 Vue + Spring Boot)
  4. 研究 OAuth2:实现微信/Google 第三方登录
  5. 阅读官方文档Spring Security 官网

💬 最后说句掏心窝的话:我当初学的时候,光是搞懂“认证”和“授权”的区别就花了三天。别怕慢,每个程序员都是从“Hello World”开始的。坚持敲代码,你也能行!


快速命令 & 配置对照表

场景 配置方式 示例
设置默认用户 application.properties spring.security.user.name=admin
自定义内存用户 Java 配置类 InMemoryUserDetailsManager
限制路径访问 HttpSecurity .requestMatchers("/admin/**").hasRole("ADMIN")
自定义登录页 formLogin().loginPage() .loginPage("/my-login")
密码加密 PasswordEncoder new BCryptPasswordEncoder()

希望这篇教程能帮你推开 Spring Security 的大门。记住:安全不是功能,而是责任。哪怕是最小的项目,也要认真对待用户数据。

加油!我在代码的世界等你 👨‍💻

评论 0

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