Springboot --- Spring Security (一)
文章部分图片来自参考资料
问题 :
- 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<AuthenticationProvider> 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;
}
这个认证方法可以做三件事 :
return an
Authentication(normally withauthenticated=true) if it can verify that the input represents a valid principal.throw an
AuthenticationExceptionif it believes that the input represents an invalid principal.return
nullif it can’t decide.
这样我们就可以知道认证一切核心认证的操作实际必须由 AuthenticationManager 来完成,ss提供了一个类AuthenticationManagerBuilder 来让我们方便地配置AuthenticationManager (例如我想用怎么样的认证方式,哪个节点不需要认证, 哪个节点需要等等),这个类就像我们平时的 helper 类一样。例如像下面这样使用 :
@Configuration
public 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<AccessDecisionVoter<? extends Object>> decisionVoters) {
super(decisionVoters);
}
public void decide(Authentication authentication, Object object,
Collection<ConfigAttribute> 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 aFilterChainProxywhich is always a@Bean, usually with a fixed name ofspringSecurityFilterChain. It is theFilterChainProxywhich contains all the security logic arranged internally as a chain (or chains) of filters. All the filters have the same API (they all implement theFilterinterface 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
WebSecurityConfigurerAdapterwith 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 theHttpSecurityconfigurer.
@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://spring.io/guides/topicals/spring-security-architecture/ (推荐一看)
- http://www.spring4all.com/article/458
- http://www.spring4all.com/article/433(推荐一看)
Springboot --- Spring Security (一)的更多相关文章
- SpringBoot + Spring Security 学习笔记(五)实现短信验证码+登录功能
在 Spring Security 中基于表单的认证模式,默认就是密码帐号登录认证,那么对于短信验证码+登录的方式,Spring Security 没有现成的接口可以使用,所以需要自己的封装一个类似的 ...
- SpringBoot + Spring Security 学习笔记(三)实现图片验证码认证
整体实现逻辑 前端在登录页面时,自动从后台获取最新的验证码图片 服务器接收获取生成验证码请求,生成验证码和对应的图片,图片响应回前端,验证码保存一份到服务器的 session 中 前端用户登录时携带当 ...
- springboot+spring security +oauth2.0 demo搭建(password模式)(认证授权端与资源服务端分离的形式)
项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖 ...
- SpringBoot + Spring Security 基本使用及个性化登录配置详解
Spring Security 基本介绍 这里就不对Spring Security进行过多的介绍了,具体的可以参考官方文档 我就只说下SpringSecurity核心功能: 认证(你是谁) 授权(你能 ...
- Spring-boot & spring.security
spring.security提供了一种身份认证框架,开发者可以在这个框架中实现各种方式的用户身份管理,比如:LDAP.MYSQL.OAUTH.Mongo等等. spring.security认证步骤 ...
- SpringBoot + Spring Security 学习笔记(二)安全认证流程源码详解
用户认证流程 UsernamePasswordAuthenticationFilter 我们直接来看UsernamePasswordAuthenticationFilter类, public clas ...
- SpringBoot + Spring Security 学习笔记(一)自定义基本使用及个性化登录配置
官方文档参考,5.1.2 中文参考文档,4.1 中文参考文档,4.1 官方文档中文翻译与源码解读 SpringSecurity 核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) ...
- SpringBoot Spring Security 核心组件 认证流程 用户权限信息获取详细讲解
前言 Spring Security 是一个安全框架, 可以简单地认为 Spring Security 是放在用户和 Spring 应用之间的一个安全屏障, 每一个 web 请求都先要经过 Sprin ...
- SpringBoot + Spring Security 学习笔记(四)记住我功能实现
记住我功能的基本原理 当用户登录发起认证请求时,会通过UsernamePasswordAuthenticationFilter进行用户认证,认证成功之后,SpringSecurity 调用前期配置好的 ...
随机推荐
- c#常用的预处理器指令
预处理器指令指导编译器在实际编译开始之前对信息进行预处理.所有的预处理器指令都是以 # 开始. #define 预处理器指令创建符号常量.#define 允许您定义一个符号,这样,通过使用符号作为传递 ...
- 微信退款证书使用c#
微信退款需要证书 data为已封装好的xml数据 具体怎么封装>打开 public string get(string data) { string cert = @"D:\certi ...
- iis部署 .net core webapi
iis部署 .net core webapi 1.修改应用程序池: IIS 发布站点,这里就不介绍 IIS 安装等.这里要修改的是应用程序池,选择“无托管代码”: 2.下载安装.net core托管捆 ...
- jzoj2941
我們可以暴力枚舉每一個人分幾個糖果,再暴力統計答案即可 每次遞歸下去可以從1-n號人,決定選多少個糖果再遞歸 #include<bits/stdc++.h> using namespace ...
- python 爬爬爬 基本函数~
https://docs.python.org/2/howto/urllib2.html#data http://zhuoqiang.me/python-urllib2-usage.html #cod ...
- Python面向对象(多态)
day24 面向对象三大特性:多态 Python原生就是多态的.
- Web应用配置虚拟主机(www.baidu.com)
最终效果:浏览器地址栏输入www.baidu.com访问时,会显示自己的网页 1.创建文件 任意盘新建一个www.baidu.com文件,在该文件夹下新建WEB-INF文件.自己写的一个html文件, ...
- Storm系列一: Storm初步
初入Storm 前言 学习Storm已经有两周左右的时间,但是认真来说学习过程确实是零零散散,遇到问题去百度一下,找到新概念再次学习,在这样的一个循环又不成体系的过程中不断学习Storm. 前人栽树, ...
- C#中ExecuteReader、ExecuteNonQuery、ExecuteScalar、SqlDataReader、SqlDataAdapter的区别
ExecuteNonQuery()执行命令对象的SQL语句,返回一个int 类型的变量,返回数据库操作之后影响的行数.适合用来验证对数据库进行增删改的情况. 2.ExecuteScalar()也可以执 ...
- 杭电OJ第11页2010-2019道题(C语言)
2010. 水仙花数 问题描述 Problem Description 春天是鲜花的季节,水仙花就是其中最迷人的代表,数学上有个水仙花数,他是这样定义的: "水仙花数"是指一个三位 ...