securuty 认证授权

6 阅读4分钟

他有6个核心类 1个配置类SecurityConfig 1个重写的过滤器 jwtAuthenticationFilter,只做token 校验 1个用户角色权限加载类 CustomUserDetailsService 2个异常处理类,一个是未认证401处理,一个是403未授权处理类。 以上类都需注册到配置类 1个token 校验类JwtTokenProvider

Snipaste_2026-04-09_17-15-49.png

Snipaste_2026-04-09_17-15-37.png 组件 类/接口 职责 JWT过滤器 JwtAuthenticationFilter 提取和验证Token,设置认证上下文 Token提供者 JwtTokenProvider 生成和验证JWT Token 用户详情服务 CustomUserDetailsService 从数据库加载用户和权限 用户详情 CustomUserDetails 封装用户信息,实现UserDetails接口 认证服务 AuthenticationService 处理登录逻辑,SSO/LDAP支持

标题

简单说一下请求过程过来: 一、先进过滤器jwtAuthenticationFilter 过滤器只有token 校验,校验不通过,方行给下面处理,校验通过的话,调用用户角色权限类加载用户权限,之后放行。 二、在security 中的看你的请求是否是方行的URL,如果配置了方行的URL,直接放行。如果是需要认证授权的 利用 FilterSecurityInterceptor 查看是否通过认证,没有交给异常处理器返回401,认证通过后查看权限,方法上加注解会会校验,没有的话异常处理返回403, ┌─────────────────────────────────────────────────────────────────────────────┐ │ 客户端请求 │ │ (浏览器/Postman/前端应用) │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ SecurityConfig │ │ (安全配置中心) │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 1. 配置过滤器链顺序 │ │ │ │ .addFilterBefore(jwtAuthenticationFilter, │ │ │ │ UsernamePasswordAuthenticationFilter.class) │ │ │ │ │ │ │ │ 2. 配置路径授权规则 │ │ │ │ .authorizeHttpRequests(auth -> auth │ │ │ │ .requestMatchers("/api/sys/auth/").permitAll() │ │ │ │ .anyRequest().authenticated() │ │ │ │ ) │ │ │ │ │ │ │ │ 3. 配置异常处理器 │ │ │ │ .exceptionHandling(exception -> exception │ │ │ │ .authenticationEntryPoint(customAuthenticationEntryPoint) │ │ │ │ .accessDeniedHandler(customAccessDeniedHandler) │ │ │ │ ) │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 过滤器链 (Filter Chain) │ │ 按配置顺序依次执行 │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ JwtAuthenticationFilter (自定义JWT过滤器) │ │ │ │ 包路径: security/filter │ │ │ │ │ │ │ │ 职责: 认证 (Authentication) - "你是谁?" │ │ │ │ ├─ 从Authorization头或Cookie提取Token │ │ │ │ ├─ 验证Token有效性 (JwtTokenProvider) │ │ │ │ ├─ 验证成功: 加载用户详情,设置SecurityContext │ │ │ │ └─ 无论成败: 一定调用 chain.doFilter() 放行 │ │ │ │ │ │ │ │ 关键点: 只做认证,不做拦截决策 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ UsernamePasswordAuthenticationFilter (Spring Security默认) │ │ │ │ 状态: 通常已禁用 (formLogin.disable()) │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ FilterSecurityInterceptor (Spring Security内部创建) │ │ │ │ │ │ │ │ 职责: 授权 (Authorization) - "你能做什么?" │ │ │ │ ├─ 检查当前请求路径的授权规则 │ │ │ │ ├─ permitAll() → 直接放行 │ │ │ │ ├─ authenticated() → 检查SecurityContext是否有认证信息 │ │ │ │ ├─ hasRole/hasAuthority() → 检查角色/权限 │ │ │ │ └─ 检查失败 → 抛出异常,进入异常处理器 │ │ │ │ │ │ │ │ 关键点: 真正的拦截决策在这里 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ Controller (业务层) │ │ ├─ @PreAuthorize("hasRole('ADMIN')") 方法级权限控制 │ │ └─ SecurityUtils.getCurrentUser() 获取当前用户信息 │ └─────────────────────────────────────────────────────────────────────────────┘ 二说一下登录步骤 先到过滤器---之后没有token放行,之后在security 配置了放行这个URL,就到了登录Controller,开始校验用户名和密码。通过后调用用户角色权限加载类,加载用户角色权限,存储到securitycontxt 上下文,返回给前端token 等信息。 用户请求 POST /api/sys/auth/login │ ▼ JwtAuthenticationFilter │ ├── 提取Token? 否(登录接口不需要Token) ├── 验证Token? 跳过 └── chain.doFilter() 放行 │ ▼ FilterSecurityInterceptor │ ├── 检查规则: /api/sys/auth/ → permitAll() └── 直接放行(不检查认证) │ ▼ AuthController.login() │ ├── AuthenticationService.authenticate() │ ├── 验证用户名密码 │ ├── 生成JWT Token (JwtTokenProvider) │ └── 返回Token和用户信息 │ ├── 设置Cookie: token=xxx (解决反向代理问题) │ └── 返回JSON: { "token": "xxx", "tokenType": "Bearer", "userId": 1, "permissions": ["sys:user:list", ...] } 三 业务请求成功场景 用户请求 GET menu/nav Header: Authorization: Bearer xxx │ ▼ JwtAuthenticationFilter │ ├── 提取Token: Bearer xxx ├── 验证Token: 有效 ✅ ├── 解析用户名: admin ├── 加载用户详情: CustomUserDetailsService ├── 设置SecurityContext: 认证信息 └── chain.doFilter() 放行 │ ▼ FilterSecurityInterceptor │ ├── 检查规则: /api → authenticated() ├── 检查SecurityContext: 有认证信息 ✅ └── 允许访问 │ ▼ SysMenuController.nav() │ └── 执行业务逻辑,返回数据 四 业务请求失败场景 4.1 无token 用户请求 GET menu/nav Header: (无Authorization) │ ▼ JwtAuthenticationFilter │ ├── 提取Token: 无 ├── 验证Token: 跳过 └── chain.doFilter() 放行(SecurityContext为空) │ ▼ FilterSecurityInterceptor │ ├── 检查规则: /api/sys/menu/nav → authenticated() ├── 检查SecurityContext: 无认证信息 ❌ ├── 抛出: AuthenticationCredentialsNotFoundException │ ▼ CustomAuthenticationEntryPoint │ └── 返回: {"code": 401, "message": "未认证,请先登录"} 4.2 权限不足 用户请求 DELETE /user/1 Header: Authorization: Bearer valid_token (普通用户Token) │ ▼ JwtAuthenticationFilter │ ├── 提取Token: 有效 ├── 验证Token: 通过 ✅ ├── 加载用户: 角色=USER ├── 设置SecurityContext: 认证信息 └── chain.doFilter() 放行 │ ▼ FilterSecurityInterceptor │ ├── 检查规则: authenticated() 通过 ✅ └── 放行到Controller │ ▼ SysUserController.delete() @PreAuthorize("hasRole('ADMIN')") │ ├── 检查角色: USER vs ADMIN ❌ ├── 抛出: AccessDeniedException │ ▼ CustomAccessDeniedHandler │ └── 返回: {"code": 403, "message": "无权限访问该资源"} 4.3 token 无效 用户请求 GET menu/nav Header: Authorization: Bearer invalid_token │ ▼ JwtAuthenticationFilter │ ├── 提取Token: Bearer invalid_token ├── 验证Token: 无效 ❌ ├── 不设置SecurityContext └── chain.doFilter() 放行 │ ▼ FilterSecurityInterceptor │ ├── 检查规则: /api/sys/menu/nav → authenticated() ├── 检查SecurityContext: 无认证信息 ❌ └── 进入 CustomAuthenticationEntryPoint (401)