You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否脱离Spring及Spring Boot使用Spring Security?求文档或实现步骤

脱离Spring/Spring Boot实现Spring Security核心功能

Spring Security的核心是过滤器链驱动的身份认证与授权逻辑,完全可以脱离Spring容器在传统Servlet项目中实现。以下是具体的实现步骤和关键代码示例:

一、依赖管理(Maven为例)

只引入Spring Security的核心与Web模块,排除所有Spring容器相关依赖,避免和现有旧库冲突:

<dependencies>
    <!-- Spring Security核心 -->
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>5.7.11</version> <!-- 选稳定的5.x版本,适配旧JDK -->
        <exclusions>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-expression</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- Spring Security Web模块,处理Servlet相关逻辑 -->
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>5.7.11</version>
        <exclusions>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </exclusions>
    </dependency>
</dependencies>

二、手动配置Security过滤器链

1. Web.xml中注册核心过滤器

在项目的web.xml中添加DelegatingFilterProxy,指定过滤器名称为springSecurityFilterChain:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <!-- 禁用Spring容器查找,手动指定过滤器实例 -->
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2. 手动构建过滤器链实例

创建一个初始化类(比如SecurityInitializer),在项目启动时手动构建FilterChainProxy(即springSecurityFilterChain),替代Spring容器的自动配置:

import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.RoleVoter;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.ArrayList;
import java.util.List;

public class SecurityInitializer implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // 1. 创建过滤器链列表
        List<SecurityFilterChain> filterChains = new ArrayList<>();
        List<javax.servlet.Filter> filters = new ArrayList<>();

        // 2. 添加核心过滤器(按Spring Security固定顺序)
        filters.add(new SecurityContextPersistenceFilter()); // 管理SecurityContext
        filters.add(createUsernamePasswordAuthFilter()); // 登录认证
        filters.add(createLogoutFilter()); // 登出
        filters.add(createFilterSecurityInterceptor()); // 授权拦截

        // 3. 绑定过滤器链到所有URL
        filterChains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/**"), filters));

        // 4. 将FilterChainProxy注册到Servlet上下文
        FilterChainProxy filterChainProxy = new FilterChainProxy(filterChains);
        sce.getServletContext().setAttribute("springSecurityFilterChain", filterChainProxy);
    }

    // 构建登录过滤器配置
    private UsernamePasswordAuthenticationFilter createUsernamePasswordAuthFilter() {
        UsernamePasswordAuthenticationFilter authFilter = new UsernamePasswordAuthenticationFilter();
        authFilter.setAuthenticationManager(createAuthenticationManager());
        authFilter.setFilterProcessesUrl("/login"); // 登录接口URL
        authFilter.setAuthenticationSuccessHandler((req, res, auth) -> res.sendRedirect("/home")); // 登录成功跳转
        authFilter.setAuthenticationFailureHandler((req, res, ex) -> res.sendRedirect("/login?error")); // 登录失败跳转
        return authFilter;
    }

    // 构建认证管理器
    private ProviderManager createAuthenticationManager() {
        List<org.springframework.security.authentication.AuthenticationProvider> providers = new ArrayList<>();
        providers.add(new CustomAuthenticationProvider()); // 自定义认证逻辑
        return new ProviderManager(providers);
    }

    // 构建登出过滤器
    private LogoutFilter createLogoutFilter() {
        return new LogoutFilter("/login?logout", new SimpleUrlLogoutSuccessHandler());
    }

    // 构建授权拦截器配置
    private FilterSecurityInterceptor createFilterSecurityInterceptor() {
        FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor();
        interceptor.setAuthenticationManager(createAuthenticationManager());
        interceptor.setAccessDecisionManager(new AffirmativeBased(List.of(new RoleVoter()))); // 基于角色的授权
        interceptor.setSecurityMetadataSource(new CustomSecurityMetadataSource()); // 自定义URL-角色映射
        return interceptor;
    }
}

然后在web.xml中注册这个监听器:

<listener>
    <listener-class>com.yourpackage.SecurityInitializer</listener-class>
</listener>

三、实现核心业务组件

1. 自定义AuthenticationProvider(认证逻辑)

实现AuthenticationProvider接口,处理用户名密码校验:

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class CustomAuthenticationProvider implements AuthenticationProvider {
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        // 从数据库/自定义数据源获取用户信息(替代UserDetailsService)
        UserDetails user = loadUserByUsername(username);
        if (user == null) {
            throw new BadCredentialsException("User not found");
        }
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new BadCredentialsException("Invalid password");
        }

        return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

    // 自定义用户加载逻辑,替代Spring的UserDetailsService
    private UserDetails loadUserByUsername(String username) {
        // 示例:从数据库查询用户,组装UserDetails
        return org.springframework.security.core.userdetails.User.builder()
                .username("admin")
                .password(passwordEncoder.encode("admin123"))
                .roles("ADMIN")
                .build();
    }
}

2. 自定义SecurityMetadataSource(URL-角色映射)

实现FilterInvocationSecurityMetadataSource接口,定义哪些URL需要哪些角色访问:

import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.util.HashMap;
import java.util.Map;
import java.util.Collection;
import java.util.List;

public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    private final Map<AntPathRequestMatcher, Collection<SimpleGrantedAuthority>> urlRolesMap = new HashMap<>();

    public CustomSecurityMetadataSource() {
        // 初始化URL-角色映射
        urlRolesMap.put(new AntPathRequestMatcher("/admin/**"), List.of(new SimpleGrantedAuthority("ROLE_ADMIN")));
        urlRolesMap.put(new AntPathRequestMatcher("/user/**"), List.of(new SimpleGrantedAuthority("ROLE_USER")));
        // 公开URL不需要角色
        urlRolesMap.put(new AntPathRequestMatcher("/login"), List.of());
        urlRolesMap.put(new AntPathRequestMatcher("/public/**"), List.of());
    }

    @Override
    public Collection<SimpleGrantedAuthority> getAttributes(Object object) throws IllegalArgumentException {
        FilterInvocation fi = (FilterInvocation) object;
        for (Map.Entry<AntPathRequestMatcher, Collection<SimpleGrantedAuthority>> entry : urlRolesMap.entrySet()) {
            if (entry.getKey().matches(fi.getHttpRequest())) {
                return entry.getValue();
            }
        }
        // 默认需要登录认证
        return List.of(new SimpleGrantedAuthority("ROLE_USER"));
    }

    @Override
    public Collection<SimpleGrantedAuthority> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

四、关键注意事项

  • 过滤器顺序不能乱:Spring Security的过滤器有固定执行顺序,必须严格按照SecurityContextPersistenceFilter → 认证过滤器 → 授权过滤器的顺序添加;
  • 避免Spring容器依赖:所有组件都用普通Java类实现,不要使用Spring的注解(如@Autowired、@Service),完全手动管理实例;
  • 密码加密必须标准化:禁止手动处理密码哈希,必须使用PasswordEncoder接口的实现(如BCryptPasswordEncoder);
  • 会话管理:如果需要控制并发登录、会话超时,可添加SessionManagementFilter和ConcurrentSessionFilter;
  • 异常处理:添加ExceptionTranslationFilter统一处理AccessDeniedException和AuthenticationException,避免直接抛出到前端。

内容的提问来源于stack exchange,提问作者Sasirekha Kumaran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:44:51