如何手搓一个Spring Security

"手搓"一个 Security 框架,实际上是为了透彻理解 Spring Security 等成熟框架背后的底层原理(如认证、授权、拦截机制)。基于现有的技术分析和实战案例,我们可以将这个过程简化为一个"极简版权限控制框架"的开发。这通常被称为"造轮子"或"徒手写安全框架"。

以下是结合 Java Web 技术栈,教你如何一步步"手搓"一个简易 Security 框架的核心步骤:

🧱 第一阶段:核心组件设计 (搭架子)

在 Spring Security 中,有 UserDetailsUserDetailsService 等概念。我们要先定义自己的核心模型。

  1. 定义用户实体 (User)

模拟框架中的 UserDetails

包含属性:用户名、密码、权限列表(例如 ["admin", "user"])。

  1. 定义认证服务 (AuthenticationService)

模拟框架中的 UserDetailsService

逻辑: 接收前端传来的用户名密码,与数据库(初期可用 Map 模拟)中的数据比对。

功能: 如果匹配成功,生成一个"登录凭证"(可以是 SessionId 或者简单的 Token 对象)。

🚧 第二阶段:拦截机制 (立屏障)

这是安全框架的"大门",所有请求必须先经过这里。

  1. 使用过滤器 (Filter) 或 拦截器 (Interceptor)

在请求到达 Controller 之前进行拦截。

排除路径: 放行登录页(/login)、静态资源、注册接口。

拦截路径: 拦截所有需要权限的接口(如 /admin/**, `/user/**)。

  1. 实现"认证"逻辑 (Authentication)

检查请求中是否携带了凭证(Cookie 中的 SessionId 或 Header 中的 Token)。

如果没有凭证,返回 401 Unauthorized 或重定向到登录页。

如果有凭证,去 Redis 或内存中校验该凭证是否有效(是否过期、是否被注销)。

🔑 第三阶段:授权逻辑 (分权限)

认证通过后,还要看用户有没有资格执行这个操作。

  1. 权限匹配

从凭证中获取当前用户的权限列表。

获取当前请求的 URL 或 方法名。

逻辑判断: 比如,请求 /admin/delete 需要 ROLE_ADMIN 权限。如果用户权限列表中包含该角色,则放行;否则返回 403 Forbidden

  1. 模拟注解功能

你可以通过 Java 反射机制,读取 Controller 方法上的自定义注解(例如 @RequireRole("ADMIN")),然后进行逻辑判断。

💻 第四阶段:代码实战 (极简版伪代码)

这里参考了常见的"徒手写 Security"教学案例,给出一个简化的逻辑流程:

1. 模拟用户登录 (认证)
java 复制代码
// 简化的伪代码
@PostMapping("/login")
public String login(String username, String password, HttpSession session) {
    // 1. 校验用户名密码 (模拟数据库查询)
    if ("admin".equals(username) && "123456".equals(password)) {
        // 2. 登录成功,将用户信息存入 Session
        session.setAttribute("user", new User("admin", Arrays.asList("admin", "user")));
        return "login success";
    }
    throw new RuntimeException("用户名或密码错误");
}
2. 拦截器进行权限校验 (授权)
java 复制代码
// 实现 HandlerInterceptor 接口
public class AuthInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        
        // 1. 获取 Session
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        
        // 2. 如果用户未登录
        if (user == null) {
            response.sendRedirect("/login"); 
            return false;
        }
        
        // 3. 权限校验逻辑 (例如:如果是访问 /admin 路径,需要 admin 角色)
        String uri = request.getRequestURI();
        if (uri.startsWith("/admin") && !user.getRoles().contains("admin")) {
            response.sendError(403, "权限不足");
            return false;
        }
        
        // 4. 校验通过,放行
        return true;
    }
}

🚀 第五阶段:进阶功能 (对标 Spring Security)

当你完成了上述基础流程,可以尝试添加以下功能来提升"逼格":

集成 Redis: 将 Session 存储在 Redis 中,实现分布式环境下的统一登录状态管理。

实现 JWT: 不使用 Session,改为生成 JWT Token,实现无状态认证。

方法级安全: 使用 AOP 切面,拦截带有特定注解(如@PreAuthorize),实现细粒度的控制。

CSRF 防护: 增加 Token 校验,防止跨站请求伪造攻击。

📌 注意点

1、密码存储必须加盐哈希

2、必须合理配置空闲超时和绝对超时时间

3、必须添加默认拒绝规则,必须防止越权访问

4、使用AOP必须主要拦截器失效的情况

5、注意路径匹配漏洞

6、记录审计、防止SQL注入

📌 总结

"手搓" Security 框架的核心在于理解 "过滤器链" 和 "领域模型"。

Spring Security 很复杂,因为它考虑了各种企业级场景(LDAP、OAuth2、RememberMe )。

你自己写的很简单,但只要包含了 "拦截请求 -> 校验身份 -> 校验权限 -> 放行/拒绝" 这一流程,你就已经掌握了其最核心的原理。

相关推荐
大傻^12 小时前
LangChain4j Spring Boot Starter:自动配置与声明式 Bean 管理
java·人工智能·spring boot·spring·langchain4j
沐硕13 小时前
《基于改进协同过滤与多目标优化的健康饮食推荐系统设计与实现》
java·python·算法·fastapi·多目标优化·饮食推荐·改进协同过滤
yhole13 小时前
springboot 修复 Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38819)
spring boot·后端·spring
大傻^13 小时前
Spring AI 2.0 MCP 协议实战:Model Context Protocol SDK 与多服务器编排
服务器·人工智能·spring
BingoGo13 小时前
Laravel 13 正式发布 使用 Laravel AI 无缝平滑升级
后端·php
愣头不青13 小时前
560.和为k的子数组
java·数据结构
共享家952713 小时前
Java入门(String类)
java·开发语言
l软件定制开发工作室13 小时前
Spring开发系列教程(34)——打包Spring Boot应用
java·spring boot·后端·spring·springboot
0xDevNull13 小时前
Spring Boot 循环依赖解决方案完全指南
java·开发语言·spring
爱丽_13 小时前
GC 怎么判定“该回收谁”:GC Roots、可达性分析、四种引用与回收算法
java·jvm·算法