Spring Security 6

简介

Spring 是非常流行和成功的 Java 应用开发框架,Spring Security 正是 Spring 家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。

WEB 安全方面的两个主要区域是“认证”和“授权”(或者访问控制),一般来说,Web 应用的安全性包括用户认(Authentication)和用户授权(Authorization)两个部分,这两点也是 Spring Security 重要核心功能。

历史

“Spring Security 开始于 2003 年年底,““spring 的 acegi 安全系统”。 起因是 Spring 开发者邮件列表中的一个问题,有人提问是否考虑提供一个基于 spring 的安全实现。

Spring Security 以“The Acegi Secutity System for Spring” 的名字始于 2013 年晚些时候。一个问题提交到 Spring 开发者的邮件列表,询问是否已经有考虑一个机遇 Spring 的安全性社区实现。那时候 Spring 的社区相对较小(相对现在)。实际上 Spring 自己在 2013 年只是一个存在于 ScourseForge 的项目,这个问题的回答是一个值得研究的领域,虽然目前时间的缺乏组织了我们对它的探索。

6 上新增的功能

  • Core

    • gh-12233 - 安全授权管理器允许自定义底层授权管理器
    • GH-12231 - 添加颁发机构集合授权管理器
  • OAuth 2.0

    • gh-12604 - 支持 AuthnRequestSigned 元数据属性
    • gh-12846 - 元数据支持多个实体和实体描述符
    • gh-11828 - (文档) - 将 saml2 元数据添加到 DSL
    • gh-12843 - (文档) - 允许从注销请求中推断信赖方
    • gh-10243 - (文档) - 允许从 SAML 响应推断信赖方
    • gh-12842 - 添加信赖方注册占位符解析组件
    • gh-12845 - 支持在已注销后发出注销响应
  • Observability

    • gh-12534 - 自定义身份验证和授权观察约定
  • Web

    • gh-12751 - 添加请求匹配器工厂类
    • gh-12847 - 通过 And 和 OrRequestMatcher 传播变量
  • Docs

    • GH-13088 - (文档) - 重新访问授权文档
    • gh-12681 - (文档) - 重新访问会话管理文档
    • gh-13062 - (文档) - 重新访问注销文档
    • gh-13089 - 重温 CSRF 文档

    相关概念

  • 主体
    英文单词:principal

    使用系统的用户或设备或从其他系统远程登录的用户等等。简单说就是谁使用系统谁就是主体。

  • 认证

    英文单词:authentication

    权限管理系统确认一个主体的身份,允许主体进入系统。简单说就是“主体”证明自己是谁。
    笼统的认为就是以前所做的登录操作。

  • 授权

    英文单词:authorization

    将操作系统的“权力”“授予”“主体”,这样主体就具备了操作系统中特定功能的能力。

注解使用

  • @Secured:判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“。
  • @PreAuthorize 注解适合进入方法前的权限验证,
  • @PostAuthorize 在方法执行后再进行权限验证,适合验证带有返回值的权限
  • @PostFilter 过滤注解,权限验证之后对数据进行过滤 留下满足要求的数据
  • @PreFilter 进入控制器之前对数据进行过滤

https://docs.spring.io/spring-security/reference/servlet/authorization/method-security.html

责任链

spring security 采用的时责任链的设计模式,再了解他之前,先了解下此种设计模式

责任链设计模式是一种行为型设计模式,它将请求的发送者和接收者解耦,将多个处理对象连成一条责任链,依次处理请求,直到请求被处理或者到达责任链的末尾。该模式常用于日志记录、权限验证、请求过滤等场景。

角色介绍

  • 抽象处理者(Handler)

抽象处理者定义了一个处理请求的接口,并保存下一个处理对象的引用。它可以是抽象类或接口。

public abstract class Handler {
    protected Handler nextHandler;

    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public abstract void handleRequest(Request request);
}
  • 具体处理者(ConcreteHandler)

具体处理者实现了抽象处理者的接口,并处理它所负责的请求。如果不能处理该请求,则将请求传递给下一个处理对象。

public class ConcreteHandlerA extends Handler {
    @Override
    public void handleRequest(Request request) {
        if (request.getType() == RequestType.TYPE_A) {
            // 处理请求
        } else {
            // 无法处理该请求,将请求传递给下一个处理对象
            if (nextHandler != null) {
                nextHandler.handleRequest(request);
            } else {
                // 如果没有下一个处理对象,则输出日志
                System.out.println("No handler available for request.");
            }
        }
    }
}
  • 客户端(Client)

客户端创建请求对象,并将其发送给第一个处理对象。客户端可以根据需要自定义处理对象的顺序,也可以动态地增加或删除处理对象。

public class Client {
    public static void main(String[] args) {
        // 创建请求对象
        Request request = new Request(RequestType.TYPE_A, "Request A");

        // 创建处理对象
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        Handler handlerC = new ConcreteHandlerC();

        // 构建责任链
        handlerA.setNextHandler(handlerB);
        handlerB.setNextHandler(handlerC);

        // 发送请求
        handlerA.handleRequest(request);
    }
}

SpringSecurity 的过滤器

Spring Security 的过滤器链是配置在 SpringMVC 的核心组件 DispatcherServlet 运行之前。也就是说,请求通过 Spring Security 的所有过滤器, 不意味着能够正常访问资源,该请求还需要通过 SpringMVC 的拦截器链。

Security Filter 通过 SecurityFilterChain 被插入到 FilterChainProxy 中。可以通过 FilterOrderRegistration 查看过滤器的顺序:28 个内置过滤器

FilterOrderRegistration() {
    Step order = new Step(INITIAL_ORDER, ORDER_STEP);
    put(DisableEncodeUrlFilter.class, order.next());
    put(ForceEagerSessionCreationFilter.class, order.next());
    put(ChannelProcessingFilter.class, order.next());
    order.next(); // gh-8105
    put(WebAsyncManagerIntegrationFilter.class, order.next());
    put(SecurityContextHolderFilter.class, order.next());
    put(SecurityContextPersistenceFilter.class, order.next());
    put(HeaderWriterFilter.class, order.next());
    put(CorsFilter.class, order.next());
    put(CsrfFilter.class, order.next());
    put(LogoutFilter.class, order.next());
    this.filterToOrder.put(
            "org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
            order.next());
    this.filterToOrder.put(
            "org.springframework.security.saml2.provider.service.web.Saml2WebSsoAuthenticationRequestFilter",
            order.next());
    put(X509AuthenticationFilter.class, order.next());
    put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
    this.filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order.next());
    this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
            order.next());
    this.filterToOrder.put(
            "org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter",
            order.next());
    put(UsernamePasswordAuthenticationFilter.class, order.next());
    order.next(); // gh-8105
    put(DefaultLoginPageGeneratingFilter.class, order.next());
    put(DefaultLogoutPageGeneratingFilter.class, order.next());
    put(ConcurrentSessionFilter.class, order.next());
    put(DigestAuthenticationFilter.class, order.next());
    this.filterToOrder.put(
            "org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter",
            order.next());
    put(BasicAuthenticationFilter.class, order.next());
    put(RequestCacheAwareFilter.class, order.next());
    put(SecurityContextHolderAwareRequestFilter.class, order.next());
    put(JaasApiIntegrationFilter.class, order.next());
    put(RememberMeAuthenticationFilter.class, order.next());
    put(AnonymousAuthenticationFilter.class, order.next());
    this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
            order.next());
    put(SessionManagementFilter.class, order.next());
    put(ExceptionTranslationFilter.class, order.next());
    put(FilterSecurityInterceptor.class, order.next());
    put(AuthorizationFilter.class, order.next());
    put(SwitchUserFilter.class, order.next());
}

15 个过滤器进行说明

  • (1)WebAsyncManagerIntegrationFilter:将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。

  • (2)SecurityContextHolderFilter/SecurityContextPersistenceFilter:在每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中,然后在该次请求处理完成之后,将 SecurityContextHolder 中关于这次请求的信息存储到一个“仓储”中,然后将 SecurityContextHolder 中的信息清除,例如在 Session 中维护一个用户的安全信息就是这个过滤器处理的。所有过滤器的入口;

  • (3)HeaderWriterFilter:用于将头信息加入响应中。

  • (4)CsrfFilter:用于处理跨站请求伪造。

  • (5)LogoutFilter:用于处理退出登录。

  • (6)UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自 /login 的请求。从表单中获取用户名和密码时,默认使用的表单 name 值为 username 和 password,这两个值可以通过设置这个过滤器的 usernameParameter 和 passwordParameter 两个参数的值进行修改。

  • (7)DefaultLoginPageGeneratingFilter:如果没有配置登录页面,那系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面。

  • (8)BasicAuthenticationFilter:检测和处理 http basic 认证。

  • (9)RequestCacheAwareFilter:用来处理请求的缓存。

  • (10)SecurityContextHolderAwareRequestFilter:主要是包装请求对象 request。

  • (11)AnonymousAuthenticationFilter:检测 SecurityContextHolder 中是否存在 Authentication 对象,如果不存在为其提供一个匿名 Authentication。

  • (12)SessionManagementFilter:管理 session 的过滤器

  • (13)ExceptionTranslationFilter:处理 AccessDeniedException 和
    AuthenticationException 异常。

  • (14)AuthorizationFilter:可以看做过滤器链的出口。

  • (15)RememberMeAuthenticationFilter:当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的 remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。

核心组件

AuthenticationManager

AuthorizationManager

ProviderManager

Authentication

AuthenticationProvider

AbstractAuthenticationToken

UserDetails

UserDetailsService

SecurityFilterChain

SecurityContextHolder

PasswordEncoder

AuthenticationEventPublisher

AuthorizationEventPublisher

AccessDeniedHandler

AuthenticationEntryPoint

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Elcker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值