Spring Security认证的方法是什么
Spring Security认证的方法是什么
今天小编给大家分享一下SpringSecurity认证的方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
前言
本文以用户名/密码验证方式为例,讲解 Spring Security 的认证流程,在此之前,需要你了解 Spring Security 用户名/密码认证的基本配置。
Spring Security 是基于过滤器的,通过一层一层的过滤器,处理认证的流程,拦截非法请求。
认证上下文的持久化
处于最前面的过滤器叫做 SecurityContextPersistenceFilter
,Spring Security 是通过 Session 来存储认证信息的,这个过滤器的 doFilter
方法在每次请求中只执行一次,作用就是,在请求时,将 Session 中的 SecurityContext 放到当前请求的线程中(如果有),在响应时,检查县城中是否有 SecurityContext,有的话将其放入 Session。可以理解为将 SecurityContext 进行 Session 范围的持久化。
认证信息的封装
接着进入 UsernamePasswordAuthenticationFilter
,这是基于用户名/密码认证过程中的主角之一。
默认情况下,这个过滤器会匹配路径为 /login
的 POST 请求,也就是 Spring Security 默认的用户名和密码登录的请求路径。
这里最关键的代码是 attemptAuthentication
方法(由 doFilter
方法调用),源码如下:
@OverridepublicAuthenticationattemptAuthentication(HttpServletRequestrequest,HttpServletResponseresponse)throwsAuthenticationException{if(this.postOnly&&!request.getMethod().equals("POST")){thrownewAuthenticationServiceException("Authenticationmethodnotsupported:"+request.getMethod());}Stringusername=obtainUsername(request);username=(username!=null)?username:"";username=username.trim();Stringpassword=obtainPassword(request);password=(password!=null)?password:"";UsernamePasswordAuthenticationTokenauthRequest=newUsernamePasswordAuthenticationToken(username,password);//Allowsubclassestosetthe"details"propertysetDetails(request,authRequest);returnthis.getAuthenticationManager().authenticate(authRequest);}
在 attemptAuthentication
方法代码的第 12 行,使用从 request 中获取到的用户名和密码,构建了一个 UsernamePasswordAuthenticationToken
对象,我们可以看到这个构造方法的代码,非常简单:
publicUsernamePasswordAuthenticationToken(Objectprincipal,Objectcredentials){super((Collection)null);this.principal=principal;this.credentials=credentials;this.setAuthenticated(false);}
只是保存了用户名和密码的引用,并且将认证状态设置为 false
,因为此时只是封装了认证信息,还没有进行认证。
我们再回到 attemptAuthentication
的代码,在方法的最后一行,将创建好的认证信息,传递给了一个 AuthenticationManager
进行认证。这里实际工作的是 AuthenticationManager
的实现类 ProviderManager
。
查找处理认证的 Provider 类
进入 ProviderManager
可以从源码中找到 authenticate
方法,代码比较长,我就不贴在这里了,你可以自行查找,我简述一下代码中的逻辑。
ProviderManager
本身不执行认证操作,它管理着一个 AuthenticationProvider
列表,当需要对一个封装好的认证信息进行认证操作的时候,它会将认证信息和它管理者的 Provider 们,逐一进行匹配,找到合适的 Provider 处理认证的具体工作。
可以这样理解,ProviderManager
是一个管理者,管理着各种各样的 Provider。当有工作要做的时候,它从来都不亲自去做,而是把不同的工作,分配给不同的 Provider 去操作。
最后,它会将 Provider 的工作成果(已认证成功的信息)返回,或者抛出异常。
那么,它是怎么将一个认证信息交给合适的 Provider 的呢?
在上一部分中,我们说到,认证信息被封装成了一个 UsernamePasswordAuthenticationToken
,它是Authentication
的子类,ProviderManager
会将这个认证信息的类型,传递个每个 Provider 的 supports
方法,由 Provider 来告诉 ProviderManager
它是不是支持这个类型的认证信息。
认证逻辑
在 Spring Security 内置的 Provider 中,与 UsernamePasswordAuthenticationToken
对应的 Provider 是 DaoAuthenticationProvider
,authenticate
方法在它的父类 AbstractUserDetailsAuthenticationProvider
中。我们来看它的 authenticate
方法:
@OverridepublicAuthenticationauthenticate(Authenticationauthentication)throwsAuthenticationException{Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class,authentication,()->this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports","OnlyUsernamePasswordAuthenticationTokenissupported"));Stringusername=determineUsername(authentication);booleancacheWasUsed=true;UserDetailsuser=this.userCache.getUserFromCache(username);if(user==null){cacheWasUsed=false;try{user=retrieveUser(username,(UsernamePasswordAuthenticationToken)authentication);}catch(UsernameNotFoundExceptionex){this.logger.debug("Failedtofinduser'"+username+"'");if(!this.hideUserNotFoundExceptions){throwex;}thrownewBadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials","Badcredentials"));}Assert.notNull(user,"retrieveUserreturnednull-aviolationoftheinterfacecontract");}try{this.preAuthenticationChecks.check(user);additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken)authentication);}catch(AuthenticationExceptionex){if(!cacheWasUsed){throwex;}//Therewasaproblem,sotryagainafterchecking//we'reusinglatestdata(i.e.notfromthecache)cacheWasUsed=false;user=retrieveUser(username,(UsernamePasswordAuthenticationToken)authentication);this.preAuthenticationChecks.check(user);additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken)authentication);}this.postAuthenticationChecks.check(user);if(!cacheWasUsed){this.userCache.putUserInCache(user);}ObjectprincipalToReturn=user;if(this.forcePrincipalAsString){principalToReturn=user.getUsername();}returncreateSuccessAuthentication(principalToReturn,authentication,user);}
代码比较长,我们说要点:
代码第 12 行,通过
retrieveUser
方法,获得UserDetails
信息,这个方法的具体实现,可以在DaoAuthenticationProvider
中找到,主要是通过UserDetailsService
的loadUserByUsername
方法,查找系统中的用户信息。代码第 25 行,通过
preAuthenticationChecks.check
方法,进行了认证前的一些校验。校验的具体实现可以在DefaultPreAuthenticationChecks
内部类中找到,主要是判断用户是否锁定、是否可用、是否过期。代码第 26 行,通过
additionalAuthenticationChecks
方法,对用户名和密码进行了校验。具体实现可以在DaoAuthenticationProvider
中找到。代码第 39 行,通过
postAuthenticationChecks.check
方法,校验了密码是否过期。具体实现可以在DefaultPostAuthenticationChecks
内部类中找到。最后,如果以上校验和认证都没有问题,则通过
createSuccessAuthentication
方法,创建成功的认证信息,并返回。此时,就成功通过了认证。
在最后的 createSuccessAuthentication
方法中,会创建一个新的 UsernamePasswordAuthenticationToken
认证信息,这个新的认证信息的认证状态为 true
。表示这是一个已经通过的认证。
这个认证信息会返回到 UsernamePasswordAuthenticationFilter
中,并作为 attemptAuthentication
方法的结果。
在 doFilter
方法中,会根据认证成功或失败的结果,调用相应的 Handler 类进行后续的处理,最后,认证的信息也会被保存在 SecurityContext 中,供后续使用。
以上就是“SpringSecurity认证的方法是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注恰卡编程网行业资讯频道。
推荐阅读
-
初识mongodb之数据插入篇(spring boot使用shiro还是secuitry好)
springboot使用shiro还是secuitry好?shiro还是springsecurity各自的优缺点追加:shiro...
-
spring(boot 自定义jar包 linux怎么部署springboot)
linux怎么部署springboot?Linux以两种部署springboot项目。部署jar包(官方推荐)在linux服务器上...
-
springboot静态资源路径虚拟映射(spring boot 中可以存放静态滋源文件的位置有)
springboot中可以存放静态滋源文件的位置有?springboot是实际不自动配置来实现的,其中静态资源配置共有是::/...
-
Spring Security 实战干货:手把手教你实现JWT Token
-
「web安全」Spring Boot eureka xstream 反序列化
-
spring中的特殊注解@RequiredArgsConstructor怎么用
spring中的特殊注解@RequiredArgsConstructor怎么用...
-
SpringBoot+Spring Security无法实现跨域怎么解决
SpringBoot+SpringSecurity无法实现跨域怎么解决...
-
Spring Security基于注解的接口角色访问控制怎么实现
SpringSecurity基于注解的接口角色访问控制怎么实现本...
-
Spring代理对象导致的获取不到原生对象注解怎么解决
Spring代理对象导致的获取不到原生对象注解怎么解决本文小编为大...
-
解析Spring漏洞及修复的方法
解析Spring漏洞及修复的方法本篇内容主要讲解“解析Spring...