Spring Security 原理分析

引言

在试题系统开发过程当中,认证方式愈来愈完善,也对Spring Security有了更加深入的理解。前端

本文,咱们一块儿来领略Spring Security的设计原理。java

原理

必备基础

ServletJava Web领域中的软件开发规范,Tomcat是实现Servlet规范的Java Web服务器。安全

package javax.servlet;

public interface Servlet {

    public void init(ServletConfig config) throws ServletException;

    public ServletConfig getServletConfig();

    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;

    public String getServletInfo();

    public void destroy();
}

Servlet长这样,生命周期十分简单,初始化init、业务逻辑service、销毁destroy服务器

简单来讲:咱们根据Servlet接口开发咱们的应用,服务器开发商根据Servlet接口开发Servlet服务器。架构

image.png

前端HTTP请求,Tomcat选择路由匹配的Servlet,若是已经实例化,直接调用service;若是未实例化,实例化后调用service,处理完以后返回响应。并发

图中示例的url统一采用小写,关于url大小写的问题,如下是结论,虽然有些url是大小写不敏感的,可是这使得表示惟一性变得困难,咱们一般应该认为大小写是敏感的。框架

There may be URLs, or parts of URLs, where case doesn't matter, but identifying these may not be easy. Users should always consider that URLs are case-sensitive.

image.png

为了在Servlet先后执行其余逻辑,定义了Filter接口,在请求先后都会执行。ide

原理分析

Spring Security官方文档摘抄的一张图:高并发

image.png

Spring Security的原理其实就是经过Servlet中的Filter技术进行实现的,经过一系列内置的或自定义的安全Filter,实现接口认证与受权。性能

image.png

Spring Security官方也给出了默认Filter的执行顺序,先执行认证的过滤器,后执行受权的过滤器,其中就有咱们经常使用的UsernamePasswordAuthenticationFilterBasicAuthenticationFilter等等。

阅读源码一个Filter源码便可理解整个认证架构设计。

注:如下代码中部分无关代码已被删减。

public class BasicAuthenticationFilter extends OncePerRequestFilter {

     @Override
     protected void doFilterInternal(HttpServletRequest request,
               HttpServletResponse response, FilterChain chain) {
          try {
               /** 从请求中获取用户名密码信息 */
               UsernamePasswordAuthenticationToken authRequest = authenticationConverter.convert(request);
               /** 若是没有相关信息,说明不是此种认证方式,执行后续过滤器 */
               if (authRequest == null) {
                    chain.doFilter(request, response);
                    return;
               }
               /** 获取用户名 */
               String username = authRequest.getName();
               /** 判断该用户是否须要认证 */
               if (authenticationIsRequired(username)) {
                    /** 尝试使用 token 进行认证 */
                    Authentication authResult = this.authenticationManager
                              .authenticate(authRequest);
                    /** 认证成功,将认证结果置入上下文 */
                    SecurityContextHolder.getContext().setAuthentication(authResult);
                    /** 认证成功相关回调 */
                    this.rememberMeServices.loginSuccess(request, response, authResult);
                    onSuccessfulAuthentication(request, response, authResult);
               }
          }
          catch (AuthenticationException failed) {
               /** 认证失败,清空当前上下文信息 */
               SecurityContextHolder.clearContext();
               /** 认证失败相关回调 */
               this.rememberMeServices.loginFail(request, response);
               onUnsuccessfulAuthentication(request, response, failed);
               /** 若是须要忽略失败,则继续执行后续过滤器 */
               if (this.ignoreFailure) {
                    chain.doFilter(request, response);
               }
               /** 不然开始执行新的认证方案 */
               else {
                    this.authenticationEntryPoint.commence(request, response, failed);
               }
               return;
          }
          /** 本过滤器执行完毕,执行后续过滤器 */
          chain.doFilter(request, response);
     }
}

其实很简单是否是?

添加自定义认证逻辑

若是默认的验证方式不知足要求,要怎么添加自定义验证方式呢?其实只须要添加自定义的Filter便可。

就好比说常见的短信验证码登陆方式:

image.png

默认不支持短信方式,咱们能够在过滤器链中植入一个自定义的短信验证过滤器,认证成功后设置认证信息便可。

SecurityContextHolder.getContext().setAuthentication(authResult);

Reactive

这个是上个月遇到的问题,尝试了一下OAuth 2.0认证架构。

image.png

其实这个架构很广泛,许多项目都采用该种架构。只不过都是采用Spring Cloud Netflix Zuul + Spring Security Resource Server的实现。

这里我尝试将Zuul换成Spring Cloud Gateway,由于Zuul的阻塞IO在网关层面实在太影响性能了。

前面已经说了,Spring Security中的认证与受权方式是经过Servlet技术套装中的Filter实现的,Tomcat提供了Servlet的运行环境。

Spring Cloud Netflix Zuul集成Spring Boot Starter Web也就是默认的Tomcat实现网关,因此Zuul中是有Servlet的运行环境的。

而非阻塞的Spring Cloud Gateway基于Spring WebFlux框架,不支持Servlet,底层采用高性能的Netty服务器。

Spring WebFluxSpring MVC的对比请看下图:

image.png

因此当Spring SecuritySpring Cloud Gateway集成时,就会出错,Spring Security须要的Servlet环境没有被知足。

这也是以前对Reactive的理解不到位而引发的错误,WebFlux环境下,应该集成Spring Security Reactive,而非默认的Spring Security

总结

经资料查阅,高性能的 Netty十分受各大互联网企业欢迎,TwitterFacebook、苹果、微博都在使用Netty,具体Netty为何更适合高并发?之后咱们一块儿学习。

相关文章
相关标签/搜索