博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Springboot --- Spring Security (一)
阅读量:5922 次
发布时间:2019-06-19

本文共 7371 字,大约阅读时间需要 24 分钟。

  文章部分图片来自参考资料

问题 :

  • Spring Security 内部实现的原理是什么

概述

         Spring Security 是个安全框架,可以提供认证,防止网络功能等功能,可以结合 spring-security-oauth 框架一起使用。本文主要讲的是几个重要的类结构,还有工作原理,工作流程会在下一篇介绍。

Spring Security 认证

      Application security boils down to two more or less independent problems: authentication (who are you?) and authorization (what are you allowed to do?).

       应用安全关注两个问题 : authentication (认证,你是谁)和 authorization (授权,你可以做什么)。

认证

        认证的目的是证明你是谁的问题,在生活中,我们证明自己的身份有多种方式:身份证证明,指纹证明等等,即是说认证的方式有多种,ss框架中认证的方式定义为 provider , 管理这些认证方式的是 providerManager ,下面我们看一下这两个类的源码(源码不完整,只为了展示内部作用) :

public interface AuthenticationProvider {	Authentication authenticate(Authentication authentication)			throws AuthenticationException;	boolean supports(Class
authentication);}public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean { private List
providers = Collections.emptyList(); public Authentication authenticate(Authentication authentication) ... for (AuthenticationProvider provider : getProviders()) { ... try { result = provider.authenticate(authentication); if (result != null) { copyDetails(authentication, result); break; } } catch (AccountStatusException e) { prepareException(e, authentication); // SEC-546: Avoid polling additional providers if auth failure is due to // invalid account status throw e; } catch (InternalAuthenticationServiceException e) { prepareException(e, authentication); throw e; } catch (AuthenticationException e) { lastException = e; } } .... eventPublisher.publishAuthenticationSuccess(result); return result; // Parent was null, or didn't authenticate (or throw an exception). if (lastException == null) { lastException = new ProviderNotFoundException(messages.getMessage( "ProviderManager.providerNotFound", new Object[] { toTest.getName() }, "No AuthenticationProvider found for {0}")); } prepareException(lastException, authentication); throw lastException; } }

        它们的关系可以用这张图 :

        可以看到 ProviderManager 内部放着一个 AuthenticationProvider (认证方式)的数组,当要认证的是否,逐个遍历调用认证的方法。而 ProviderManager 继承一个 AuthenticationManager  ,上面的authenticate()方法正是来自 AuthenticationManager  。

public interface AuthenticationManager {	Authentication authenticate(Authentication authentication)			throws AuthenticationException;}

      这个认证方法可以做三件事 :

  1. return an Authentication (normally with authenticated=true) if it can verify that the input represents a valid principal.

  2. throw an AuthenticationException if it believes that the input represents an invalid principal.

  3. return null if it can’t decide.

        这样我们就可以知道认证一切核心认证的操作实际必须由  AuthenticationManager  来完成,ss提供了一个类AuthenticationManagerBuilder 来让我们方便地配置AuthenticationManager  (例如我想用怎么样的认证方式,哪个节点不需要认证, 哪个节点需要等等),这个类就像我们平时的 helper 类一样。例如像下面这样使用 :

@Configurationpublic class ApplicationSecurity extends WebSecurityConfigurerAdapter {  @Autowired  DataSource dataSource;   ... // web stuff here  @Override  public configure(AuthenticationManagerBuilder builder) {    builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")      .password("secret").roles("USER");  }}

      继承 WebSecurityConfigurerAdapter ,重写 configure 方法,然后配置 AuthenticationManagerBuilder 。

授权

        和 AuthenticationManager(的实现类) 持有一个 privoder 列表一样,AccessDecisionManager (的实现类)持有 AccessDecisionVoter 列表 , DecisionVoter 是从名字就知道是判断授权的策略。 例如 AccessDecisionManager 的一个实现类,授权的过程

public class AffirmativeBased extends AbstractAccessDecisionManager {	public AffirmativeBased(List
> decisionVoters) { super(decisionVoters); } public void decide(Authentication authentication, Object object, Collection
configAttributes) throws AccessDeniedException { int deny = 0; for (AccessDecisionVoter voter : getDecisionVoters()) { int result = voter.vote(authentication, object, configAttributes); if (logger.isDebugEnabled()) { logger.debug("Voter: " + voter + ", returned: " + result); } switch (result) { case AccessDecisionVoter.ACCESS_GRANTED: return; case AccessDecisionVoter.ACCESS_DENIED: deny++; break; default: break; } } if (deny > 0) { throw new AccessDeniedException(messages.getMessage( "AbstractAccessDecisionManager.accessDenied", "Access is denied")); } // To get this far, every AccessDecisionVoter abstained checkAllowIfAllAbstainDecisions(); }}

 

 

Spring Security 原理

      Spring Security in the web tier (for UIs and HTTP back ends) is based on Servlet Filters

         SS在http后台中起作用主要是基于 Servlet Filters 的,我们先来看看什么是 Filter 是如何作用在 Servlet 中的。

      可以看到不同的过滤器作用在 Servlet 之前,多个形成的就是一条过滤器链( Filters Chain ),每个Filter 有个 Order 顺序,可以通过 @Order 来设置Filter 的 Order ,设置前后顺序。SS本身也是一个 Filter ,使用一个代理,委托了一个 Filter Chain ,如下图 :

          In fact there is even one more layer of indirection in the security filter: it is usually installed in the container as a DelegatingFilterProxy, which does not have to be a Spring @Bean. The proxy delegates to a FilterChainProxy which is always a @Bean, usually with a fixed name of springSecurityFilterChain. It is the FilterChainProxy which contains all the security logic arranged internally as a chain (or chains) of filters. All the filters have the same API (they all implement the Filter interface from the Servlet Spec) and they all have the opportunity to veto the rest of the chain.

           springSecurityFilterChain 是个接口,DefaultSecurityFilterChain 是它的实现类,而DefaultSecurityFilterChain  内部存在这一个 Filters 列表,关于SS中的过滤器和他们的执行顺序(Order)可以查看 ,当我们需要自定义Filter的时候就会用到。 当请求到来时,在 ss 里边的 Filter就会作用请求,如下图  :

创建一个自定义 Filter Chain

        SS本身有个 Filter Chain ,我们新创建的 Filter Chain 的 Order 设置高点,关于为什么会有自定义 Filter Chain 这样的场景我们可以看官方文档的举得例子。

     Many applications have completely different access rules for one set of resources compared to another. For example an application that hosts a UI and a backing API might support cookie-based authentication with a redirect to a login page for the UI parts, and token-based authentication with a 401 response to unauthenticated requests for the API parts. Each set of resources has its own WebSecurityConfigurerAdapter with a unique order and a its own request matcher. If the matching rules overlap the earliest ordered filter chain will win.

 

@Configuration@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {  @Override  protected void configure(HttpSecurity http) throws Exception {    http.antMatcher("/foo/**")     ...;  }}

请求匹配和分发授权

        A security filter chain (or equivalently a WebSecurityConfigurerAdapter) has a request matcher that is used for deciding whether to apply it to an HTTP request. Once the decision is made to apply a particular filter chain, no others are applied. But within a filter chain you can have more fine grained control of authorization by setting additional matchers in the HttpSecurity configurer.

@Configuration@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {  @Override  protected void configure(HttpSecurity http) throws Exception {    http.antMatcher("/foo/**")      .authorizeRequests()        .antMatchers("/foo/bar").hasRole("BAR")        .antMatchers("/foo/spam").hasRole("SPAM")        .anyRequest().isAuthenticated();  }}

补充

       更多关于SS 的原理看 。

总结

        介绍了几个SS 中重要的几个类,包括认证和授权,明白了 SS 可以工作的原因是作为在 Servlet 之前的 Filter .

参考资料

  • 这几个参考资料写得很好,推荐一读
  • (推荐一看)
  • (推荐一看)

转载于:https://www.cnblogs.com/Benjious/p/10588466.html

你可能感兴趣的文章
python全栈开发笔记---------数据类型---字典方法
查看>>
ios项目中引用其他开源项目
查看>>
分治优化决策单调性
查看>>
Nginx与Apache简单对比
查看>>
常见的HTTP返回状态值
查看>>
Centos防火墙添加IP白名单
查看>>
OpenCV学习笔记——疑问
查看>>
Mac使用brew安装nginx,并解决端口访问权限问题
查看>>
【云图】如何建立北京三甲医院云图,不用数据库持有自己数据!
查看>>
分布拟合——正态/拉普拉斯/对数高斯/瑞利 分布
查看>>
Codeforces Round #331 (Div. 2)
查看>>
构造 hihocoder 1257 Snake Carpet (15北京I)
查看>>
Queue学习
查看>>
构造水题 Codeforces Round #206 (Div. 2) A. Vasya and Digital Root
查看>>
nRF5 SDK for Mesh(一) 介绍和下载源码
查看>>
SPRING 集成 KAFKA 发送消息
查看>>
spark-reduceByKey算子
查看>>
Visual C#网络编程技术与实践(配光盘)(网络编程系列丛书)
查看>>
C语言队列的实现
查看>>
需要知道的一些Java优化技术
查看>>