LJF-Framework 第14章 LjfSecurity适配SpringSecurity
LJF-Framework 第14章 LjfSecurity适配SpringSecurity
一、先了解一下SpringSecurity
1、简介
Spring Security是一个Java框架,用于保护应用程序的安全性。它提供了一套全面的安全解决方案,包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念,可以轻松地集成到任何基于Spring的应用程序中。它支持多种身份验证选项和授权策略,开发人员可以根据需要选择适合的方式。此外,Spring Security还提供了一些附加功能,如集成第三方身份验证提供商和单点登录,以及会话管理和密码编码等。总之,Spring Security是一个强大且易于使用的框架,可以帮助开发人员提高应用程序的安全性和可靠性。
2、我们先了解servlet的使用
Spring Security 通过使用标准的 Servlet Filter 与 Servlet 容器集成。这意味着它适用于任何在 Servlet 容器中运行的应用程序。更具体地说,你不需要在你基于 Servlet 的应用程序中使用 Spring 来利用 Spring Security。
3、springboot 的自动配置
Spring Boot Security Auto Configuration
@EnableWebSecurity
@Configuration
public class DefaultSecurityConfig {@Bean@ConditionalOnMissingBean(UserDetailsService.class)InMemoryUserDetailsManager inMemoryUserDetailsManager() { String generatedPassword = // ...;return new InMemoryUserDetailsManager(User.withUsername("user").password(generatedPassword).roles("ROLE_USER").build());}@Bean@ConditionalOnMissingBean(AuthenticationEventPublisher.class)DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher(ApplicationEventPublisher delegate) { return new DefaultAuthenticationEventPublisher(delegate);}
}
-
添加了 @EnableWebSecurity 注解。(在其他方面,它将 Spring Security 的默认 Filter chain 作为 @Bean 发布)。
-
发布一个 UserDetailsService @Bean,其用户名是 user,密码是随机生成的,会被记录到控制台。
-
发布一个 AuthenticationEventPublisher @Bean,用于发布认证事件。
Spring Boot 将任何以 @Bean 形式发布的 Filter 添加到应用程序的 filter chain 中。这意味着,结合 Spring Boot 使用 @EnableWebSecurity 会自动为每个请求注册 Spring Security 的 filter chain。
4、Security Filter
Security Filter 是通过 SecurityFilterChain API 插入 FilterChainProxy 中的。
这些 filter 可以用于许多不同的目的,如 认证、 授权、 漏洞保护 等等。filter 是按照特定的顺序执行的,以保证它们在正确的时间被调用,例如,执行认证的 Filter 应该在执行授权的 Filter 之前被调用。一般来说,没有必要知道 Spring Security 的 Filter 的顺序。但是,有些时候知道顺序是有好处的,如果你想知道它们,可以查看 FilterOrderRegistration 代码。
为了解释上面这段话,让我们考虑以下 security 配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.csrf(Customizer.withDefaults()).authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated()).httpBasic(Customizer.withDefaults()).formLogin(Customizer.withDefaults());return http.build();}}
上述配置中的 Filter 顺序如下:
Filter | 添加者 |
---|---|
CsrfFilter | HttpSecurity#csrf |
UsernamePasswordAuthenticationFilter | HttpSecurity#formLogin |
BasicAuthenticationFilter | HttpSecurity#httpBasic |
AuthorizationFilter | HttpSecurity#authorizeHttpRequests |
首先,调用 CsrfFilter 来防止 CSRF 攻击。
其次,认证 filter 被调用以认证请求。
第三,调用 AuthorizationFilter 来授权该请求。
到此基本内容了解就够了,剩下的我们用的时候实践学习。
二、我们的框架得适应一下
package com.ljf.framework.security;import java.util.function.BiFunction;/*** 说明:客制化安全配置,要个客制化单独实现的,包括用户帐号密码的验证等** @Auther: lijinfeng* @Date: 2022/12/12*/
public class LjfSecurityConfig {/*** 用户校验函数,验证用户信息,正确返回用户对象 错误返回0L*/public BiFunction<String, String, LjfUser> checkUserHandler = (u, p) -> (LjfUser) () -> 0L;/*** 设置登录用户校验函数** @param checkUserHandler* @return*/public void setCheckUserHandler(BiFunction<String, String, LjfUser> checkUserHandler) {this.checkUserHandler = checkUserHandler;}/*** 获取登录用户校验函数** @return*/public BiFunction<String, String, LjfUser> getCheckUserHandler() {return checkUserHandler;}}
如上所示,我们将认证返回的信息由用户ID 改成了 用户对象,它是一个接口类型,方便我们使用的时候定义本项目的用户对象。
三、新增安全框架参数配置类
1、LjfSecurityProperties
package com.ljf.framework.security;import java.util.Arrays;
import java.util.Collections;
import java.util.List;/*** 描述 : 安全配置类* <p>* 版本 作者 时间 内容* 1.0 lijinfeng 2025-04-10 09:32 create*/
public class LjfSecurityProperties {/*** 登录路径*/private String loginPath;/*** 拦截路径 默认拦截所有*/private List<String> includeList = Arrays.asList("/**");/*** 排除路径*/private List<String> excludeList = Arrays.asList("");public String getLoginPath() {return loginPath;}public void setLoginPath(String loginPath) {this.loginPath = loginPath;}public List<String> getIncludeList() {return includeList;}public void setIncludeList(List includeList) {this.includeList = includeList;}public List<String> getExcludeList() {return excludeList;}public void setExcludeList(List excludeList) {this.excludeList = excludeList;}}
我这里就做了简单的测试,各位可以多加点需要用到的属性
2、LjfSecurityConfigFactory
弄一个工厂类,来配置我们设置的参数属性
package com.ljf.framework.security;import com.ljf.framework.exception.LjfExceptionEnum;
import com.ljf.framework.exception.LjfSecurityException;
import com.ljf.framework.utils.LjfUtils;import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;/*** LjfSecurity配置文件的构建工厂类* 用于手动读取配置文件初始化 LjfSecurityConfig 对象,只有在非IOC环境下你才会用到此类*/
public class LjfSecurityConfigFactory {private LjfSecurityConfigFactory() {}/*** 配置文件*/public static <