"手搓"一个 Security 框架,实际上是为了透彻理解 Spring Security 等成熟框架背后的底层原理(如认证、授权、拦截机制)。基于现有的技术分析和实战案例,我们可以将这个过程简化为一个"极简版权限控制框架"的开发。这通常被称为"造轮子"或"徒手写安全框架"。
以下是结合 Java Web 技术栈,教你如何一步步"手搓"一个简易 Security 框架的核心步骤:
🧱 第一阶段:核心组件设计 (搭架子)
在 Spring Security 中,有 UserDetails、UserDetailsService 等概念。我们要先定义自己的核心模型。
- 定义用户实体 (User)
模拟框架中的 UserDetails。
包含属性:用户名、密码、权限列表(例如 ["admin", "user"])。
- 定义认证服务 (AuthenticationService)
模拟框架中的 UserDetailsService。
逻辑: 接收前端传来的用户名密码,与数据库(初期可用 Map 模拟)中的数据比对。
功能: 如果匹配成功,生成一个"登录凭证"(可以是 SessionId 或者简单的 Token 对象)。
🚧 第二阶段:拦截机制 (立屏障)
这是安全框架的"大门",所有请求必须先经过这里。
- 使用过滤器 (Filter) 或 拦截器 (Interceptor)
在请求到达 Controller 之前进行拦截。
排除路径: 放行登录页(/login)、静态资源、注册接口。
拦截路径: 拦截所有需要权限的接口(如 /admin/**, `/user/**)。
- 实现"认证"逻辑 (Authentication)
检查请求中是否携带了凭证(Cookie 中的 SessionId 或 Header 中的 Token)。
如果没有凭证,返回 401 Unauthorized 或重定向到登录页。
如果有凭证,去 Redis 或内存中校验该凭证是否有效(是否过期、是否被注销)。
🔑 第三阶段:授权逻辑 (分权限)
认证通过后,还要看用户有没有资格执行这个操作。
- 权限匹配
从凭证中获取当前用户的权限列表。
获取当前请求的 URL 或 方法名。
逻辑判断: 比如,请求 /admin/delete 需要 ROLE_ADMIN 权限。如果用户权限列表中包含该角色,则放行;否则返回 403 Forbidden。
- 模拟注解功能
你可以通过 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 )。
你自己写的很简单,但只要包含了 "拦截请求 -> 校验身份 -> 校验权限 -> 放行/拒绝" 这一流程,你就已经掌握了其最核心的原理。