GenericFilterBean,
而GenericFilterBean implements Filter
private volatile Filter delegate;
请看他的dofilter方法,
[crayon-584d49a298ae9606368754/]本文http://www.paymoon.com:8001/index.php/2016/12/07/how-do-ss4-start-and-work/ 如果转载请联系i@paymoon.com
GenericFilterBean,
而GenericFilterBean implements Filter
private volatile Filter delegate;
请看他的dofilter方法,
[crayon-584d49a298ae9606368754/]本文http://www.paymoon.com:8001/index.php/2016/12/07/how-do-ss4-start-and-work/ 如果转载请联系i@paymoon.com
UsernamePasswordAuthenticationFilter.attemptAuthentication(req, res) 用户的参数拦截最终实现者
UserDetailsService .loadUserByUsername(String username) 系统用户信息的最终实现者
上述两class分别为认证过程中一个用户的信息拦截,一个从系统中拿用户。
SimpleUrlAuthenticationSuccessHandler.onAuthenticationSuccess(req, res)
AuthenticationFailureHandler.onAuthenticationFailure(req, res)
上述两class分别为认证成功和失败后的跳转过程。
所以如果想自定义,继承他们,重写相关方法,然后在xml里面做下配置即可。
配置如下:
[crayon-584d49a2984ea900042627/] [crayon-584d49a2984f5773134295/]AbstractSecurityInterceptor.doFilter(req, res): 拦截url并走到授权的filter
根据其类中的成员变量,可知还有:
authenticationManager(默认实现是UserDetailService),见认证第二部分代码,这里是提供系统用户信息。
securityMetadataSource (默认实现是FilterInvocationSecurityMetadataSource),提供url的角色
accessDecisionManager(默认实现是AccessDecisionManager.decide),对上两个类中用户角色和url角色进行比对,如果角色符合,则向下走,否则抛出AccessDeniedException
配置如下:
[crayon-584d49a2984fc203251749/]所以这就很明显了,当系统有自定义需求时,(如我们的用户信息不能直接配置在xml里面,也有可能没有数据源,只有接口的时候,我们就需要重继承authenticationManager类[有文章写ss4的第四种用法为重改这些class,我强烈建议继承之]),需要实现这三个class(authenticationManager我们已经在认证实现)
继承UsernamePasswordAuthenticationFilter的意义
可以看这个类的属性可知,当我们获取request里面的用户,密码不是username,password时(Spring Security默认是这两个),我们可以自定义之
当我们有密码加密,需要在之后做校验时,我们也需要在这里进行对密码进行加密。
本文http://www.paymoon.com:8001/index.php/2016/12/07/spring-security-4-principle-some-important-class/ 如果转载请联系i@paymoon.com继承authenticationManager的意义
刚刚也说过,如我们的用户信息不能直接配置在xml里面,也有可能没有数据源,只有接口的时候,我们就需要重继承authenticationManager类
继承认证通过的跳转类
SimpleUrlAuthenticationSuccessHandler.onAuthenticationSuccess(req, res)
AuthenticationFailureHandler.onAuthenticationFailure(req, res)
目的在于我们login后,可能不想返回到某个jsp,或者此jsp我们根本不在本项目中,或根本不在一个机器中,我们只能返回统一的标准json接口,这时候就要用这两个class重写跳转,方便我们返回接口,跳转时可能还会涉及到跨域,到实战会讲。
继承AbstractSecurityInterceptor
有人会想这就是一个filter, 我继承它干嘛呢,其实我们看到Spring Security实现的多细致多深,可是别忘了,SS4只能做到URL的控制粒度,如果我们想做数据粒度的控制,比如leader可以看到整个team的数据,当前team player只能看到他自己的数据,我们怎么做呢,我们需要自己写实现,在url的授权通过后,走我们自己的实现,这时候继承这个filter就非常重要了。
继承authenticationManager,这个就不用再说了,用户信息和角色,btw一般在比对角色的时候,都会从redis里面拿数据
继承securityMetadataSource,这个是url的角色,当我们要汇全当前url所有角色时,还有可能是我们的角色有自己的继承关系,如admin是manager的上级,我们需要继承这个,写自己的实现,以方便拿到所有的角色。
继承AccessDecisionManager,这个类的存在意义就不用再多说,比对角色是否符合就在这里决定,符合向后走[有可能就会走到我们刚说的数据权限],不符合throw exception,
[crayon-584d49a298505470128246/] 其实这是一个总的比较类,在Spring Security里面,对于角色匹配,还有投票机制,即如果全部通过投票,则有权访问,也有一票决定权,不过因为那种细的粒度一般难以遇到,所以这里先不表。大家好,今天晚上很荣幸和大家一起,分享和探讨Spring Security的入门,使用,原理和相关问题。
我先做下自我介绍,花名龙遥,做Java有四年了,在第三方支付做的时间长一点,对分步式计算,存储有一点研究。
Spring Security 4 是我们上个月在做一个新产品中用到的,用的时间并不长,我就把我用到的功能,相关原理分享给大家,如果有问题希望和大家一起探讨。
我先给大家发一下分享的目录,如下:
[概念]了解基于资源的权限管理方式、SS4如何实现权限的原理
[模型]掌握权限数据模型
[基本功能]实现认证、授权。
[基本功能]基于URL/操作 实现资源权限管理
[进阶]密码加密处理
[进阶]CSRF攻击方式/防御/使用
[进阶]前端与后端的脱离
[进阶]token的存储:redis集中式方法
[进阶]跨域的处理
[高级]自定义:与实际的企业web项目整合开发的方法
[进阶]定制user provider
自定义 认证的过滤器
自定义认证过滤器【authenticationSuccessHandler、authenticationFailureHandler】
自定义filter,包含 authenticationManager,accessDecisionManager,securityMetadataSource
[高级]分步式:远程调用/Jar包管理
二、相关原理
1.1 、[3w1h]Spring security 4
1) what SSH4是什么
2 )who [使用对象]谁需要使用
需要对资源保护的系统/模块
3) why Spring security 4 '
http://www.paymoon.com:8001/index.php/2016/12/07/ss4why-are-spring-security-4/
4 )How 原理是怎样,怎么使用,使用到哪种程度?
在实战前,我们先简单了解下在Spring Security中的认证与授权过程,
三、实战
二个项目
四、问题
1、使用问题
从只知道一个名词到上线使用
如何从只知道概念到第一个案例
2、使用问题
失败跳转导致csrf没发现
如何发现dao里做验证
url跳转,做了一个controller
controller里获取用户信息
跨域问题两个方案,servlet归本溯源
3、从3迁移到4的问题
4、扩展问题【定制与分步式】
浏览顺序,可以跳过目标,从二原理到三的实战,实战中会穿插目标的各种实现
第一个案例,使用的是SS3,不过不耽误我们认识Spring Security的认证,授权的实现过程,我已经放在了GitHub上。
github地址:https://github.com/stevenlii/spring_security_example
环境依赖:
Eclipse/Spring tool Suite
Maven
Tomcat
搭建过程, Eclipse中新建常规的Maven Web项目
pom.xml添加依赖
[crayon-584d49a297e01037738368/]web.xml配置
[crayon-584d49a297e0c236719583/] 我也经常这样写: [crayon-584d49a297e12707637979/]filter拦截,[SS4层面]源码与启动原理/工作模式中讲过
[crayon-584d49a297e17714181550/]一切基于xml配置,applicationContext-security就是SS4中主要的配置,
我们先配置一个数据全面在xml里面的案例
[crayon-584d49a297e1d278773285/]这个是最简单的配置,数据都在xml里面,所有http相关的基于url的配置全部都在http里面,配置包含两个,一个是<http>标签里面关于intercept-url 的资源url和角色描述的权限,一个是<authentication-manager>里面的用户和角色。
本文http://www.paymoon.com:8001/index.php/2016/12/08/spring-security-4-in-action-the-first-demo/ 如果转载请联系i@paymoon.com默认只需完成以上两个配置,启动服务器
用浏览器打开这个Web应用的任意页面,都会跳转到一个登录页,这个登录页面是Spring Security自动生成的。
在登录页面输入错误的用户名密码,就会登录失败并有提示。输入正确的用户名密码,则登录成功,就可以进入Web应用的页面。
这是最简单版本的实现。
本文http://www.paymoon.com:8001/index.php/2016/12/08/spring-security-4-in-action-the-first-demo/ 如果转载请联系i@paymoon.com但是我们马上发现了两个问题,一是login页面,样式我们会想自定义,二是用户信息,我们不能配置在xml里面了。
以及,
如果我们的其它服务,是模块化的,或者说是分步式设计的,可能你想用的页面,根本就没在这个项目下,甚至都不在一个机器上,这时候调不了login.jsp了,怎么办?
登录的用户名不是username/password怎么办?
我们如何定义url级别和数据权限?
这时候请关注第二个案例。
本文http://www.paymoon.com:8001/index.php/2016/12/08/spring-security-4-in-action-the-first-demo/ 如果转载请联系i@paymoon.com想省事就这样配置:
[crayon-584d49a296b29623092543/]这两个效果不太一样,access是能获取用户信息的,security则就相反了,用户信息会被忽略,这两个配置很有用,下面会讲到。
完整配置如下:
[crayon-584d49a296b2e092233967/]相关页面代码
login.jsp [crayon-584d49a296b34624271130/] [crayon-584d49a296b39219481130/] 两个方法都是post请求,大家会注意到一个地方: <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> 这个就是CSRF了,与SS3不同,他是SS4里面默认都会开启的,为了安全,防止恶意的CSRF攻击,Spring Security需要校验form表单中的hidden域提交的内容。 关于CSRF可以插播一下,他是什么东东 [Spring Security 4]CSRF攻击方式/防御/使用 – PayMoon贝明实验室 www.paymoon.com:8001/index.php/2016/12/08/csrf-attack-and-defence/当然,因为开启了CSRF,需要在每次提交数据里面都加上CSRF,如果你有别的安全措施,或者不想加,可以在xml里面不用的,方法如下:
<csrf disabled="true"/> |
否则如果不加hidden这一段,会报错
登录的问题好像解决了,但是,如果我们的其它服务,是模块化的,或者说是分步式设计的,可能你想用的页面,根本就没在这个项目下,甚至都不在一个机器上,这时候调不了login.jsp了,怎么办?
登录的用户名不是username/password怎么办
那我们就只能提供服务了,提供能够返回类似json这种数据格式的服务,也就是前端调用我们提供的login服务,我们返回成功与否的判断+数据。
这就要自定义认证过程了
在重写之前
我们需要重新看一下SS4的认证过程,找到其登录过程和跳转机制
参考如下
[Spring Security 4][原理]几个相关重要的几个class – PayMoon贝明实验室 http://www.paymoon.com:8001/index.php/2016/12/07/spring-security-4-principle-some-important-class/
可知我们需要继承实现UsernamePasswordAuthenticationFilter
先上一下实现配置过程
[crayon-584d49a296b42400859067/] 我们在把filter加在login的时候用,需要用到<b:property name="filterProcessesUrl" value="/login" />
<custom-filter ref="myAuthenticationFilter" position="FORM_LOGIN_FILTER" />
这样,我们就可以在自定义handler里面做自定义跳转了。
那么怎么跳转呢
还记得Successhanlder吗
[crayon-584d49a296b4a181097493/]需要把我们的数据,序列化为json,就可以了。
问题来了,
因为这里面没有springmvc,我们怎么写数据呢,回本溯源,直接使用servlet的print方法即可。
实现这个之后,只要通过项目的login就可以走进登录,并且校验通过或者失败后,就会返回我们预期的json,
关于跨域的解决办法,我有写过博客,大家可以参考
JAVA WEB支持CORS 跨域访问 – PayMoon贝明实验室
http://www.paymoon.com:8001/index.php/2016/05/30/java-web-support-cors-visit/
跨域问题的解决办法Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. – PayMoon贝明实验室
再接着这个说一句,如果跨域需要自己造轮子,或者容器tomcat版本低还不支持,可以自己写filter解决跨域问题。
print方法如下,Access-Control-Allow-Origin是域名过滤,下面的一些参数是支持的header, Method等
[crayon-584d49a296b53801042959/]这样登陆的问题,从界面到分布式我们就解决了。
该用户来源的问题了:
我们如何自定义数据来源
如:从数据库中获取
刚刚说到,用户来源问题是provider里面提供的,可以看标签,那我们就可以在这里面自定义provider,我们先说通过数据库的方式
先看一下之前xml的方式
[crayon-584d49a296b59110946908/]user-service就是我们说的provider,如果我们想自定义,
需要先在配置文件里面配置好数据源,然后通过sql的方式,加载数据,
配置好数据源
[crayon-584d49a296b5f382560242/]数据模型这里也提供了一份,可以看github上,模型就是按照我们之前介绍的权限模型,有初始化的数据,
配置文件sql写法
[crayon-584d49a296b65948970682/]在这种情况下我们看下密码加密方式
密码加密有可逆和不可逆,很多,这里不是重点,不过提一下,spring4最近使用bcrpt的多,和传统md5的hash加密不同,他的执行慢,解密成本大,所以用时间换了安全。
上面代码注释的部分,就是加密的部分,是md5的salt加密方式
如果我们想要的数据,根本不在可获知的数据源上,我们只有接口,或者说,我们用户的提供方式,想自己写,那怎么办呢
自定义
要了解自定义,就得知道。在哪里进行认证的 dao
根据
[Spring Security 4][原理]几个相关重要的几个class – PayMoon贝明实验室 http://www.paymoon.com:8001/index.php/2016/12/07/spring-security-4-principle-some-important-class/
所以我们继承实现UserDetailsService类就可以了
从父类得知,在这个类里面我们把用户提取出来,并且也提供出来角色,这个后面会用到以及是否锁定,账号是否过期等
从这个类和刚刚的UsernamePasswordAuthenticationFilter类,我们可以得知,密码加密的方法不在配置,而是在程序里面做就行了,这样也方便了我们自定义密码加密。
从这里面获取的用户,我们可以生成用户token,然后存储在集中式的缓存服务器上,保证用户的单点登录。
单点的话以后更新..
这就解决了用户认证,分布式,密码加密等的诸多过程
然后就是授权过程。
授权过程
我们的用户已经有了provider,所以我们就只有过滤出资源的角色,然后和用户的角色进行比对,通过就放行即可
相关的实现类,仍然是根据
[Spring Security 4][原理]几个相关重要的几个class – PayMoon贝明实验室 http://www.paymoon.com:8001/index.php/2016/12/07/spring-security-4-principle-some-important-class/
所以我们继承实现相关url的角色实现和角色比对类就可以了
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。
CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
CSRF的原理其实它完全是以用户的身份去执行,而应用程序和浏览器很难去判断这是CSRF攻击还是合法请求。
那么,防御方法也就是针对这个来设计了。
主要有以下几种方法,简单讲一下:
通过检查请求页面的来源,识别从站外发起的请求,也就能防御CSRF了。
每次用户提交内容时,要求其在表单中填写验证码,提交后对其进行检测。
验证码机制是:服务器生成一个验证码,发送给客户端,以图片形式显示。然后客户填写后,发回服务器,对比验证。
CSRF能成功的一个重要原因是:攻击者能预知和伪造请求中的关键字段,因此,在请求中放入攻击者不能伪造的信息就能防御CSRF。
token就是在请求中加入一个随机参数token,服务器进行验证。
个人猜测SS4的CSRF是通过POST+Token的方式走的,即把token随机生成,然后hidden传输,具体机制知道的朋友也可以探讨下
本章涵盖
Spark带来了什么
Spark组件 Spark程序流 Spark生态系统 下载并启动spark-in-action虚拟机Apache Spark是一个快速,通用的分布式计算平台。听起来像市场宣传,然而这确实是最适合他的标签。
Apache Spark真的给大数据空间带来了革命。 Spark可以有效地利用内存,并且可以执行等效作业比Hadoop的MapReduce快10到100倍。除此之外,Spark的创建者设法抽象出一个事实,即你正在处理一组机器,而是给你一组基于集合的API。使用Spark的集合感觉像使用本地Scala,Java或Python集合,但Spark的集合引用分布在许多节点上的数据。这些集合的操作被转换成复杂的并行程序,而用户不必知道事实,这是一个真正强大的概念。
在本章中,我们首先阐述了Spark的主要功能,并将Spark与其自然的前身:Hadoop的MapReduce进行比较。
然后,我们简要探讨Hadoop的生态系统 - 一个与Hadoop一起用于大数据操作的工具和语言的集合,以了解Spark如何适应。
我们简要概述Spark的组件,并向您展示典型的Spark程序如何使用简单的“Hello World”示例。
最后,我们帮助您下载并设置我们为在书中运行示例而准备的spark-in-action虚拟机。
我们已经尽最大努力为Spark架构,其组件,运行时环境和API编写了全面的指南,同时提供了具体的示例和现实案例研究。通过阅读本书,更重要的是,通过筛选示例,您将获得编写自己的高质量Spark程序和管理Spark应用程序所需的知识和技能。
1.1.2 MapReduce 缺点
虽然Hadoop是当今大数据革命的基础,并且被积极使用和维护,但它仍然有它的缺点,他们主要关于它的Map-Reduce组件。 MapReduce作业结果需要存储在HDFS中,才能被其他作业使用。 由于这个原因,MapReduce本身就不适合迭代算法。
此外,许多种类的问题不容易适合MapReduce的两步模式,并将每个问题分解为一系列这两个操作可能很困难。 有时,API可能很麻烦。
Hadoop是一个相当低级的框架,所以无数的工具已经出现了:用于导入和导出数据的工具,用于操作数据的高级语言和框架,用于实时处理的工具等。 它们都带来额外的复杂性和要求,这使任何环境复杂化。 Spark解决了许多这些问题。
Spark API比传统的MapReduce API更容易使用。 要将附录A中的经典字数示例实现为MapReduce作业,您需要三个类:设置作业的主类,一个Mapper和一个Reducer,每个10行长,给出或取几个。
相比之下,以下是对Scala编写的同一个Spark程序所需要的:
[crayon-5863703d89df6602678501/] 如图1.1,显示此图形。 Spark支持Scala,Java,Python和R编程语言,因此可供更广泛的受众访问。 尽管支持Java,Spark可以利用Scala的多功能性,灵活性和函数式编程概念,这些概念更适合于数据分析。 Python和R在数据科学家和科学界中广泛传播,这使得那些用户与Java和Scala开发人员相提并论。 此外,Spark shell(read-eval-print loop [REPL])提供了一个交互式控制台,可用于实验和想法测试。 没有必要编译和部署只是为了发现一些东西不工作(再次)。 REPL甚至可用于在完整的数据集上启动作业。 [caption id="attachment_1158" align="alignnone" width="1642"] 图1.1 字数计数程序(word-count)演示了Spark的简洁性和简单性。 该程序显示在左侧的Hadoop的MapReduce框架中,右侧是一个Spark Scala程序。[/caption]Spark由多个专用组件组成。 这些是Spark Core,Spark SQL,Spark Streaming,Spark GraphX和Spark MLlib,如图1.2所示。 这些组件使Spark成为一个功能齐全的统一平台:它可以用于以前必须使用几个不同框架完成的许多任务。 以下是每个Spark组件的简要说明。
Spark Core包含运行作业所需的其他组件所需的基本Spark功能。 其中最重要的是弹性分布式数据集(RDD),这是Spark API的主要元素。 它是具有适用于数据集的操作和转换的项目的分布式集合的抽象。 它具有弹性,因为它能够在节点故障的情况下重建数据集。
图1.2 主要Spark组件和各种运行时交互和存储选项
Spark Core包含用于访问各种文件系统的逻辑,例如HDFS,GlusterFS,Amazon S3等。 它还提供了具有广播变量和累加器的计算节点之间的信息共享的手段。 其他基本功能,如网络,安全,调度和数据混排,也是Spark Core的一部分。
Spark SQL提供了使用Spark和Hive SQL(HiveQL)支持的SQL子集操作大型分布式结构化数据集的功能。 通过在Spark 1.3中引入数据框架,并在Spark 1.6中引入了DataSets,简化了结构化数据的处理并实现了激进的性能优化,Spark SQL成为了最重要的Spark组件之一。 Spark SQL还可以用于从各种结构化格式和数据源读取和写入数据,例如JavaScript对象符号(JSON)文件,Parquet文件(允许与数据一起存储模式的越来越流行的文件格式) ,关系数据库,Hive等。
DataFrames和DataSet在某些时候的操作转换为对RDDs的操作,并作为普通Spark作业执行。 Spark SQL提供了一个称为Catalyst的查询优化框架,可以通过自定义优化规则进行扩展。 Spark SQL还包括Thrift服务器,外部系统(如商业智能工具)可以使用Thrift服务器通过Spark SQL使用传统的JDBC和ODBC协议查询数据。
Spark Streaming是一个从各种来源获取实时流数据的框架。 支持的流媒体源包括HDFS,Kafka,Flume,Twitter,ZeroMQ和自定义。 Spark Streaming操作从故障自动恢复,这对于在线数据处理很重要。 Spark Streaming表示使用离散流(DStreams)的流数据,它周期性地创建包含在上一个时间窗口期间进入的数据的RDD。 Spark Streaming可以与单个程序中的其他Spark组件组合,通过机器学习,SQL和图形操作实现统一的实时处理。 这在Hadoop生态系统中是独一无二的。 从Spark 2.0开始,新的结构化流API使Spark流程序更类似于Spark批处理程序。
Spark MLlib是从加州大学伯克利分校的MLbase项目开发的机器学习算法库。 支持的算法包括逻辑回归,朴素贝叶斯分类,支持向量机(SVM),决策树,随机森林,线性回归和k均值聚类。 Apache Mahout是一个现有的开源项目,提供在Hadoop上运行的分布式机器学习算法的实现。 虽然Apache Mahout更成熟,但Spark MLlib和Mahout都包含一组类似的机器学习算法。 但是Mahout从MapReduce迁移到Spark,他们必须在未来合并。 Spark MLlib处理用于转换数据集的机器学习模型,表示为RDD或DataFrames。
图形是包括顶点和连接它们的边的数据结构。 GraphX提供了用于构建图形的功能,表示为图形RDD:EdgeRDD和VertexRDD。 GraphX包含最重要的图论理论的实现,例如页面排名,连接组件,最短路径,SVD ++等。 它还提供了Pregel消息传递API,用于由Apache Giraph实现的大规模图处理的相同API,这是一个具有图算法实现和运行在Hadoop上的项目。
Spark 实战更多文章:[翻译]Spark In Action – PayMoon贝明实验室 http://www.paymoon.com:8001/index.php/2016/12/27/spark-in-action-foreword/