幼儿饰品瑜伽美体用品美文
投稿投诉
美文创意
爱情通信
用品婚姻
爱好看病
美体软件
影音星座
瑜伽周边
星座办公
饰品塑形
搞笑减肥
幼儿两性
智家潮品

SpringSecurity认证流程分

4月20日 辞凤阙投稿
  1。认证流程分析
  SpringSecurity中默认的一套登录流程是非常完善并且严谨的。但是项目需求非常多样化,很多时候,我们可能还需要对SpringSecinity登录流程进行定制,定制的前提是开发者先深刻理解SpringSecurity登录流程,然后在此基础之上,完成对登录流程的定制。本文将从头梳理SpringSecurity登录流程,并通过几个常见的登录定制案例,深刻地理解SpringSecurity登录流程。
  本章涉及的主要知识点有:登录流程分析。配置多个数据源。添加登录验证码。1。1登录流程分析
  要搞清楚SpringSecurity认证流程,我们得先认识与之相关的三个基本组件(Authentication对象在前面文章种己经做过介绍,这里不再赘述):AuthenticationManager、ProviderManager以及AuthenticationProvider,同时还要去了解接入认证功能的过滤器AbstractAuthenticationProcessingFilter,这四个类搞明白了,基本上认证流程也就清楚了,下面我们逐个分析一下。1。1。1AuthenticationManager
  从名称上可以看出,AuthenticationManager是一个认证管理器,它定义了SpringSecurity过滤器要如何执行认证操作。AuthenticationManager在认证成功后,会返回一个Authentication对象,这个Authentication对象会被设置到SecurityContextHolder中。如果开发者不想用SpringSecurity提供的一套认证机制,那么也可以自定义认证流程,认证成功后,手动将Authentication存入SecurityContextHolder中。publicinterfaceAuthenticationManager{Authenticationauthenticate(Authenticationvar1)throwsAuthenticationE}
  从AuthenticationManager的源码中可以看到,AuthenticationManager对传入的Authentication对象进行身份认证,此时传入的Authentication参数只有用户名密码等简单的属性,如果认证成功,返回的Authentication的属性会得到完全填充,包括用户所具备的角色信息。AuthenticationManager是一个接口,它有着诸多的实现类,开发者也可以自定义AuthenticationManager的实现类,不过在实际应用中,我们使用最多的是ProviderManager,在SpringSecurity框架中,默认也是使用ProviderManager。1。1。2AuthenticationProvider
  SpringSecurity支持多种不同的认证方式,不同的认证方式对应不同的身份类型,AuthenticationProvider就是针对不同的身份类型执行具体的身份认证。例如,常见的DaoAuthenticationProvider用来支持用户名密码登录认证,RememberMeAuthenticationProvider用来支持记住我的认证。publicinterfaceAuthenticationProvider{Authenticationauthenticate(Authenticationvar1)throwsAuthenticationEbooleansupports(C?var1);}authenticate方法用来执行具体的身份忧证。supports方法用来判断当前AuthenticationProvider是否支持对应的身份类型。
  当使用用户名密码的方式登录时,对应的AuthenticationProvider实现类是DaoAuthenticationProvider,而DaoAuthenticationProvider继承自AbstractUserDetailsAuthenticationProvider并且没有重写authenticate方法,所以具体的认证逻辑在AbstractUserDetailsAuthenticationProvider的authenticate方法中。我们就从AbstractUserDetailsAuthenticationProvider开始看起:
  查看代码一开始先声明一个用户缓存对象userCache,默认情况下没有启用缓存对象。hideUserNotFoundExceptions表示是否隐藏用户名查找失败的异常,默认为true,为了确保系统安全,用户在登录失败时只会给出一个模糊提示,例如用户名或密码输入错误在SpringSecurity内部,如果用户名查找失败,则会抛出UsernameNotFoundException异常,但是该异常会被自动隐藏,转而通过一个BadCredentialsException异常来代替它,这样,开发者在处理登录失败异常时,无论是用户名输入错误还是密码输入错误,收到的总是BadCredentialsException,这样做的一个好处是可以避免新手程序员将用户名输入错误和密码输入错误两个异常分开提示。forcePrincipalAsString表示是否强制将Principal对象当成字符串来处理,默认是falser,Authentication中的Principal属性类型是一个Object,正常来说,通过Principal属性可以获取到当前登录用户对象(即UserDetails),但是如果forcePrincipalAsString设置为true,则Authentication中的Principal属性返回就是当前登录用户名,而不是用户对象。preAuthenticationChecks对象则是用于做用户状态检査,在用户认证过程中,需要检验用户状态是否正常,例如账户是否被锁定、账户是否可用、账户是否过期等。postAuthenticationChecks对象主要负责在密码校验成功后,检査密码是否过期。additionalAuthenticationChecks是一个抽象方法,主要就是校验密码,具体的实现在DaoAuthenticationProvider中。authenticate方法就是核心的校验方法了。在方法中,首先从登录数据中获取用户名,然后根据用户名去缓存中查询用户对象,如果査询不到,则根据用户名调用retrieveUser方法从数据库中加载用户;如果没有加载到用户,则抛出异常(用户不存在异常会被隐藏)。拿到用户对象之后,首先调用check方法进行用户状态检査,然后调用additionalAuthenticationChecks方法进行密码的校验操作,最后调用postAuthenticationChecks。check方法检査密码是否过期,当所有步骤都顺利完成后,调用createSuccessAuthentication方法创建一个认证后的UsernamePasswordAuthenticationToken对象并返回,认证后的对象中包含了认证主体、凭证以及角色等信息。
  这就是AbstractUserDetailsAuthenticationProvider类的工作流程,有几个抽象方法是在DaoAuthenticationProvider中实现的,我们再来看一下DaoAuthenticationProvider中的定义:
  查看代码首先定义了USERNOTFOUNDPASSWORD常量,这个是当用户查找失败时的默认密码;passwordEncoder是一个密码加密和比对工具,这个在后面会有专门的介绍,这里先不做过多解释;userNotFoundEncodedPassword变量则用来保存默认密码加密后的值;userDetailsService是一个用户查找工具,userDetailsService在前面己经讲过,这里不再赘述;userDetailsPasswordService则用来提供密码修改服务。在DaoAuthenticationProvider的构造方法中,默认就会指定PasswordEncoder,当然开发者也可以通过set方法自定义PasswordEncoder。additionalAuthenticationchecks方法主要进行密码校验,该方法第一个参数userDetails是从数据库中查询出来的用户对象,第二个参数authentication则是登录用户输入的参数。从这两个参数中分别提取出来用户密码,然后调用passwordEncoder。matches方法进行密码比对。retrieveUser方法则是获取用户对象的方法,具体做法就是调用UserDetailsServiceloadUserByUsername方法去数据库中查询。在retrieveUser方法中,有一个值得关注的地方。在该方法一开始,首先会调用prepareTimingAttackProtection方法,该方法的作用是使用PasswordEncoder对常量USERNOTFOUNDPASSWORD进行加密,将加密结果保存在userNotFoundEncodedPassword变量中。当根据用户名查找用户时,如果抛出了UsernameNotFoundException异常,则调用mitigateAgainstTimingAttack方法进行密码比对由有读者会说,用户都没查找到,怎么比对密码?需要注意,在调用mitigateAgainstTimingAttack方法进行密码比对时,使用了userNotFoundEncodedPassword变量作为默认密码和登录请求传来的用户密码进行比对,这是一个一开始就注定要失败的密码比对,那么为什么还要进行比对呢?这主要是为了避免旁道攻击(Sidechannelattack)。如果根据用户名査找用户失败,就直接抛出异常而不进行密码比对,那么黑客经过大量的测试,就会发现有的请求耗费时间明显小于其他请求,那么进而可以得出该请求的用户名是一个不存在的用户名(因为用户名不存在,所以不需要密码比对,进而节省时间),这样就可以获取到系统信息。为了避免这一问题,所以当用户查找失败时,也会调用mitigateAgainstTimingAttack方法进行密码比对,这样就可以迷惑黑客。createSuccessAuthentication方法则是在登录成功后,创建一个全新的UsernamePasswordAuthenticationToken对象,同时会判断是否需要进行密码升级,如果需要进行密码升级,就会在该方法中进行加密方案升級。通过对AbstractUserDetailsAuthenticationProvider和DaoAuthenticationProvider的讲解,相信你己经很明白AuthenticationProvider中的认证逻辑了。
  在密码学中,旁道攻击(Sidechannelattack)又称侧信道攻击、边信道攻击。这种攻击方式不是暴力破解或者是研究加密算法的弱点。它是基于从密码系统的物理实现中获取信息,比如时间、功率消耗、电磁泄漏等,这些信息可被利用于对系统的进一步破解。1。1。3ProviderManager
  ProviderManager是AuthenticationManager的一个重要实现类,正在开始学习之前,我们先通过一幅图来了解一下ProviderManager和AuthenticationProvider之间的关系,如图31所示。
  图31
  在SpringSecurity中,由于系统可能同时支持多种不同的认证方式,例如同时支持用户名密码认证、RememberMe认证、手机号码动态认证等,而不同的认证方式对应了不同的AuthenticationProvider,所以一个完整的认证流程可能由多个AuthenticationProvider来提供。
  多个AuthenticationProvider将组成一个列表,这个列表将由ProviderManager代理。换句话说,在ProviderManager中存在一个AuthenticationProvider列表,在ProviderManager中遍历列表中的每一个AuthenticationProvider去执行身份认证,最终得到认证结果。
  ProviderManager本身也可以再配置一个AuthenticationManager作为parent,这样当ProviderManager认证失败之后,就可以进入到parent中再次进行认证。理论上来说,ProviderManager的parent可以是任意类型的AuthenticationManager,但是通常都是由ProviderManager来扮演parent的角色,也就是ProviderManager是ProviderManager的parent。
  ProviderManager本身也可以有多个,多个ProviderManager共用同一个parent,当存在多个过滤器链的时候非常有用。当存在多个过滤器链时,不同的路径可能对应不同的认证方式,但是不同路径可能又会同时存在一些共有的认证方式,这些共有的认证方式可以在parent中统一处理。
  根据上面的介绍,图32是ProviderManager和AuthenticationProvider关系图。
  图32
  我们重点看一下ProviderManager中的authenticate方法:
  查看代码
  这段源码的逻辑还是非常清晰的,我们分析一下:首先获取authentication对象的类型。分别定义当前认证过程抛出的异常、parent中认证时抛出的异常、当前认证结果以及parent中认证结果对应的变量。getProviders方法用来获取当前ProviderManager所代理的所有AuthenticationProvider对象,遍历这些AuthenticationProvider对象进行身份认证。判断当前AuthenticationProvider是否支持当前Authentication对象,要是不支持,则继续处理列表中的下一个AuthenticationProvider对象调用provider。authenticate方法进行身份认证,如果认证成功,返回认证后的Authentication对象,同时调用copyDetails方法给Authentication对象的details属性赋值,由于可能是多个AuthenticationProvider执行认证操作,所以如果抛出异常,则通过lastException变量来记录。在for循环执行完成后,如果result还是没有值,说明所有的AuthenticationProvider都认证失败,此时如果parent不为空,则调用parent的authenticate方法进行认证。接下来,如果result不为空,就将result中的凭证擦除,防止泄漏,如果使用了用户名密码的方式登录,那么所谓的擦除实际上就是将密码字段设置为null,同时将登录成功的事件发布出去(发布登录成功事件需要parentResult为null。如果parentResult不为null,表示在parent中已经认证成功了,认证成功的事件也己经在parent中发布出去了,这样会导致认证成功的事件重复发布)。如果用户认证成功,此时就将result返回,后面的代码也就不再执行了。如果前面没能返回result,说明认证失败。如果lastException为null,说明parent为null或者没有认证亦或者认证失败了但是没有抛出异常,此时构造ProviderNotFoundException异常赋值给lastException。如果parentException为null,发布认证失败事件(如果parentException不为null,则说明认证失败事件已经发布过了)。最后抛出lastException异常。
  这就是ProviderManager中authenticate方法的身份认证逻辑,其他方法的源码要相对简单很多,在这里就不一一解释了,
  现在,大家已经熟悉了Authentication、AuthenticationManager、AuthenticationProvider以及ProviderManager的工作原理了,接下来的问题就是这些组件如何跟登录关联起来?这就涉及一个重要的过滤器AbstractAuthenticationProcessingFilter。1。1。4AbstractAuthenticationProcessingFilter
  作为SpringSecurity过滤器链中的一环,AbstractAuthenticationProcessingFilter可以用来处理任何提交给它的身份认证,图33描述了AbstractAuthenticationProcessingFilter的工作流程:
  图33
  图中显示的流程是一个通用的架构。
  AbstractAuthenticationProcessingFilter作为一个抽象类,如果使用用户名密码的方式登录,那么它对应的实现类是UsernamePasswordAuthenticationF构造出来的Authentication对象则是UsernamePasswordAuthenticationToken。至于AuthenticationManager,前面已经说过,一般情况下它的实现类就是ProviderManager,这里在ProviderManager中进行认证,认证成功就会进入认证成功的回调,否则进入认证失败的回调。因此,我们可以对上面的流程图再做进一步细化,如图34所示。
  图34
  前面第2章中所涉及的认证流程基本上就是这样,我们来大致梳理一下:当用户提交登录请求时,UsernamePasswordAuthenticationFilter会从当前请求HttpServletRequest中提取出登录用户名密码,然后创建出一个UsernamePasswordAuthenticationToken对象。UsernamePasswordAuthenticationToken对象将被传入ProviderManager中进行具体的认证操作。如果认证失败,则SecurityContextHolder中相关信息将被清除,登录失败回调也会被调用,如果认证成功,则会进行登录信息存储、Session并发处理、登录成功事件发布以及登录成功方法回调等操作。
  这是认证的一个大致流程。接下来我们结合AbstractAuthenticationProcessingFilter和UsernamePasswordAuthenticationFilter的源码来看一下。
  先来看AbstractAuthenticationProcessingFilter源码(部分核心代码):
  查看代码首先通过requiresAuthentication方法来判断当前请求是不是登录认证请求,如果是认证请求,就执行接下来的认证代码;如果不是认证请求,则直接继续走剩余的过滤器即可。调用attemptAuthentication方法来获取一个经过认证后的Authentication对象,attemptAuthentication方法是一个抽象方法,具体实现在它的子类UsernamePasswordAuthenticationFilter中。认证成功后,通过sessionStrategy。onAuthentication方法来处理session并发问题。continueChainBeforeSuccessfulAuthentication变量用来判断请求是否还需要继续向下走,默认情况下该参数的值为false,即认证成功后,后续的过滤器将不再执行了。unsuccessfulAuthentication方法用来处理认证失败事宜,主要做了三件事:从SecurityContextHolder中清除数据;清除Cookie等信息;调用认证失败的回调方法。successfulAuthentication方法主要用来处理认证成功事宜,主要做了四件事:向SecurityContextHolder中存入用户信息;处理C发布认证成功事件,这个事件类型InteractiveAuthenticationSuccessEvent,表示通过一些自动交互的方式认证成功,例如通过RememberMe的方式登录;调用认证成功的回调方法。
  这就是AbstractAuthenticationProcessingFilter大致上所做的事情,还有一个抽象方法attemptAuthentication是在它的继承类UsernamePasswordAuthenticationFilter中实现的,接下来我们来看下UsernamePasswordAuthenticationFilter类:
  查看代码首先声明了默认情况下登录表单的用户名字段和密码字段,用户名字段的key默认是username,密码字段的key默认是password。当然,这两个字段也可以自定义,自定义的方式就是我们在SecurityConfig中配置的。usernameParameter(uname)和。passwordParameter(passwd)(参考前几节)在UsernamePasswordAuthenticationFilter过滤器构建的时候,指定了当前过滤器只用来处理登录请求,默认的登录请求是login,当然开发者也可以自行配置。接下来就是最重要的attemptAuthentication方法了,在该方法中,首先确认请求是post类型;然后通过obtainUsername和obtainPassword方法分别从请求中提取出用户名和密码,具体的提取过程就是调用request。getParameter方法;拿到登录请求传来的用户名密码之后,构造出一个authRequest,然后调用getAuthenticationManager()。authenticate方法进行认证,这就进入到我们前面所说的ProviderManager的流程中了,具体认证过程就不再赘述了。
  以上就是整个认证流程。
  搞懂了认证流程,那么接下来如果想要自定义一些认证方式,就会非常容易了,比如定义多个数据源、添加登录校验码等。下面,我们将通过两个案例,来活学活用上面所讲的认证流程。
投诉 评论 转载

夏季来临前常喝这3种水,感冒少眼睛亮人也不爱生闷气了,太养人花者,华也,本草之精华。中药花茶品种繁多,功效不尽相同,春季有哪几款花茶最值得喝?江苏省中西医结合医院副主任中药师何丹丹向大家推荐爱生闷气玫瑰花茶玫瑰花……VR显示面板将破千万块,OLED为何缺席?随着VR硬件设备出货量的增加,VR显示面板市场规模快速增长。近日,显示行业供应链研究咨询机构DSCC发布了最新报告,用于虚拟现实(VR)的显示面板的出货量将在2022年首次达到……新短节目亮相,羽生结弦奠定北京冬奥大热门基础羽生在全日锦标赛的短节目中拿到111。31分,离世界纪录仅差0。51分。但是就得分的问题而言,国内赛的分数是不被国际滑联承认的,而且一般情况下国内赛打分比起被国际滑联承认的国际……不造车的华为发布新车,背后是利益博弈,也是鸿蒙的一次机会12月23日的华为冬季旗舰产品发布会,压轴的不是备受期待的P50Pocket折叠屏手机、更不是华为智能眼镜、WATCHD智能手表等电子消费品,而是两辆号称按照百万豪车的标准设计……秋日走进香零山来源:人民网人民日报海外版香零山风光。来自网络秋日,走进香零山村,绿树翠竹掩映,好一片恬静安详的怡人世界,桑榆飘香,溪流纵横。香零山位于湖南永州市零陵区茆江桥……极乐世界之星2号,用来做墓葬的卫星你见过吗?人死了之后上天堂?太空殡葬为您服务!近日,参与北斗系统设计的科学家徐颖在一场科普讲座提到有一颗卫星叫做极乐世界2号,这颗卫星是用来做太空殡葬服务的,据说,你可以将自己的骨……勒布朗1578,安东尼爆发,湖人轻取火箭,谁留意老詹,提前退3554,半场结束火箭暂时落后湖人19分,我们先来看一下双方球员的半场数据,火箭一方泰特4分4板、伍德8分7板、波特8分6板、格林3分、戈登7分、申京5分3板2断;湖人一方贝兹……焦裕禄长女焦守凤现仍住在旧院子里2019年,河南省兰考县原县委书记焦裕禄获得最美奋斗者个人称号,这时,他已经离开人世55年。在焦裕禄任职期间,他亲民爱民,迎难而上,无私奉献,这些宝贵的精神财富,被后人称……张美娥做10年群演,凭西游降魔篇爆红,从150元涨到3万一天文臻本以63岁高龄初登荧屏,在别人退休的年纪,她却在横店群演界闯出了一片天,甚至自嘲招美的虽然不敢去,但是招丑的敢。她就是星女郎张美娥,更是《西游降魔篇》中荒野四大……雪上加霜?郭艾伦吃技犯被驱逐,会缺席和广东队的元旦大战吗?128109,凭借着全队七人得分上双,辽宁男篮最终以19分的大胜优势兵不血刃击败了福建男篮,拿下比赛的同时,也避免了两连败的发生。随着艾伦、大韩、金金的复出,球队正重新步入正轨……央视面对面丨我不是外人哈萨克斯坦小伙儿鲁斯兰的中国情缘点击查看视频7月25日至30日,第二届中国国际消费品博览会在海南海口举办。这是全国首个以消费精品为主题的国家级展会和亚太地区规模最大的消费精品展。海南国际经济发展局……SpringSecurity认证流程分1。认证流程分析SpringSecurity中默认的一套登录流程是非常完善并且严谨的。但是项目需求非常多样化,很多时候,我们可能还需要对SpringSecinity登录流……
看世界01法国15个顶级旅游景点姚明下狠手!曝CBA名哨违规遭篮协重罚,或就此告别中国篮坛陈好复出真的是逆生长的明星哥与姐(小说)孩子不爱吃蔬菜?做一份这样的蔬菜卷饼,好吃到停不下来央视采访不能开美颜,杨紫热巴关晓彤等,都被打回原型总要来一趟甘肃的吧美军铩羽阿富汗,57年前毛主席的伟大论断再次被验证纽卡可能会选择的五位教练!你认为谁能带领纽卡崛起?北航成功发射亚太空间合作组织大学生小卫星1樱邀而至圆通赏花弗雷德落后的时候我们相信自己能赢,对球队的攻击力很有信心

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找漯河衢州兴义眉山桂林阳泉玉溪简阳山东遂宁永城新余梧州洛阳泸州温州临汾清远营口常熟浙江大连桐乡宜昌