• Spring Security 核心解读(一)整体架构


    前提

    开源项目一手文档基本都在github,标准文档基本都在官网。
    最好的文档就是官网;
    在前些年,Apache下还有个比较流行的权限框架 Shiro,但是随着Spring Security (以下简称 Security)的流行,逐渐边缘化。其实这类框架整体设计都大差不差,都是基于一系列的过滤器或者其他拦截手段实现增强。

    整体架构

    Servlet 整体的过滤器模型

    在这里插入图片描述
    这一块属于 Servlet 基础,过滤器算是Servlet核心功能之一,需重点掌握。

    Security 过滤器链

    Security 在 Servlet 过滤器上定义了一个 自己的过滤器(这个过滤器使用了委托者设计模式)
    在这里插入图片描述
    可以看到,Servlet 过滤器链上,不仅有 Security 的过滤器还有 Spring Boot 的一些过滤器,但是这里我们重点关注圈起来的那个过滤器(链)
    再对比官方的这个图
    在这里插入图片描述
    就更好理解了。

    自定义过滤器

    我们自定义的过滤器基本都是在 Security 这个过滤器链上面的,通过编排不同的顺序,实现想要的功能。
    在这之前,我们先看看Security默认的过滤器链上有哪些过滤器官方列表
    这里为了照顾,访问不了官网的,简单截个图。
    在这里插入图片描述
    在这里插入图片描述
    但不是所有过滤器默认都开启了的。
    在这里插入图片描述
    上面那个链是,Spring 全局的过滤器链,里面第四个过滤器委托给了下面那个 Security 的过滤器链,在 Security 的过滤器链中,可以看到默认有14个过滤器。
    其中有几个重点关注的是:

    • SecurityContextPersistenceFilter (即将过时,替代者为 SecurityContextHolderFilter),其功能为,支持默认的基于 Cookie 的登录形式;对于新接触认证授权的开发者,要明白一点,不管什么实现方案,每一次进行鉴权,其本质会进行一次登录认证,只是方式不同而已
    • LogoutFilter 注销登录的过滤器,默认的url为 /logout,要实现自定义退出可以参考
    • UsernamePasswordAuthenticationFilter 大部分开发者,开始接触 Security 都是模仿这个 过滤器实现的自定义登录
    • AnonymousAuthenticationFilter 在 Security 中,认证没有通过或者没有匹配上认证过滤器的请求,最终会被定义为匿名认证,这也是一种认证结果,在权限中也有相关的配置。

    其他的过滤器根据自己的需求,调整。

    实际开发解决方案

    在实际开发中,目前通常采用前后端分离的形式;有的前端对Cookie 不太友好;因此,为了统一,大部分开发者会采用 header 认证方式。
    这样实现起码会有两个点需要调整

    1. 调整默认认证成功的处理方式
      默认配置下,认证成功会跳转到一个指定的页面;现在大多会把这个跳转交给前端。
    2. 改为header 传递认证参数后,默认的过滤器就不支持了,需要定义一个 过滤器,解析header,并进行认证;个人推荐将这个认证过滤器放在
      AnonymousAuthenticationFilter 的前面,因为前面还有些其他认证过滤器,如果自定义的过滤器太靠前,可能会被其他认证过滤器(比如上面提到的 SecurityContextPersistenceFilter 以及 SecurityContextHolderFilter)给覆盖掉认证信息,当然这要取决实际的优先级,万一你就想自定义的认证认证过滤器优先级低一点呢
      在这里插入图片描述
      可以看到,这两个认证过滤器不管你是否已经认证,会直接覆盖掉认证信息。

    一个替代cookie认证的filter

    提供一个简单实现,具体业务逻辑,开发者自己填充

    package authorization.filter;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.context.SecurityContext;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.util.StringUtils;
    import org.springframework.web.filter.OncePerRequestFilter;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Collections;
    
    public class JwtAuthenticationFilter extends OncePerRequestFilter {
    	private final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
    
    	@Override
    	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
    			throws ServletException, IOException {
    		String token = request.getHeader("token");
    		if (!StringUtils.hasText(token)) {
    			filterChain.doFilter(request, response);
    			return;
    		}
    		try {
    			UsernamePasswordAuthenticationToken authenticationToken
    					= UsernamePasswordAuthenticationToken.authenticated("zhangsan", "zs", Collections.emptyList());
    			SecurityContext context = SecurityContextHolder.createEmptyContext();
    			context.setAuthentication(authenticationToken);
    			SecurityContextHolder.setContext(context);
    			filterChain.doFilter(request, response);
    		}
    		finally {
    			SecurityContextHolder.clearContext();
    		}
    	}
    
    	@Override
    	protected boolean shouldNotFilterErrorDispatch() {
    		return true;
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    其他组件,后续抽时间再整理整理

  • 相关阅读:
    关于Http和Https
    关于spring的xml文件中的xmlns,xsi,schemaLocation
    MySQL实现的一点总结(五)
    开源表单流程设计器有哪几个突出的优势特点?
    如何快速创建腾讯云MySQL数据库并远程连接?
    简单宠物网页设计作业 静态HTML动物介绍网页作业 DW宠物网站模板下载 大学生简单野生动物网页作品代码
    【转】多台服务器共享session问题
    C++面向对象
    git相关知识记录
    HTML<var> 标签
  • 原文地址:https://blog.csdn.net/tergou/article/details/130911795