珠海建设网站的公司哪家好,wordpress 电影模版,深圳网站建设领先,用ps做网站切片1、SpringSecurity认证流程包含哪几个子流程#xff1f; 1#xff09;账号验证 2#xff09;密码验证 3#xff09;记住我—Cookie记录 4#xff09;登录成功—页面跳转
2、UsernamePasswordAuthenticationFilter 在SpringSecurity中处理认证逻辑是在UsernamePas…1、SpringSecurity认证流程包含哪几个子流程 1账号验证 2密码验证 3记住我—Cookie记录 4登录成功—页面跳转
2、UsernamePasswordAuthenticationFilter 在SpringSecurity中处理认证逻辑是在UsernamePasswordAuthenticationFilter这个过滤 器中实现的UsernamePasswordAuthenticationFilter 继承于 AbstractAuthenticationProcessingFilter 这个父类。 当请求进来时在doFilter 方法中会对请求进行拦截判断请求是否需要认证若不需要 认证则放行否则执行认证逻辑 1 注意UsernamePasswordAuthenticationFilter 类中是没有 doFilter 方法的doFilter 方法是继承自父类 UsernamePasswordAuthenticationFilter 的。 doFilter 方法代码如下
//执行过滤的方法所有请求都走这个方法
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {//请求和应答类型转换HttpServletRequest request (HttpServletRequest)req;HttpServletResponse response (HttpServletResponse)res;//判断请求是否需要认证处理若不需要认证处理则直接放行if (!this.requiresAuthentication(request, response)) {//放行往下走chain.doFilter(request, response);} else {//执行到这里进行认证处理if (this.logger.isDebugEnabled()) {this.logger.debug(Request is to process authentication);}Authentication authResult;try {//处理认证然后返回 Authentication 认证对象//重点authResult this.attemptAuthentication(request, response);//认证失败if (authResult null) {return;}//认证成功之后注册sessionthis.sessionStrategy.onAuthentication(authResult, request, response);} catch (InternalAuthenticationServiceException var8) {this.logger.error(An internal error occurred while trying to authenticate the user., var8);this.unsuccessfulAuthentication(request, response, var8);return;} catch (AuthenticationException var9) {this.unsuccessfulAuthentication(request, response, var9);return;}//if (this.continueChainBeforeSuccessfulAuthentication) {chain.doFilter(request, response);}//认证成功后的处理this.successfulAuthentication(request, response, chain, authResult);}}protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {if (this.logger.isDebugEnabled()) {this.logger.debug(Authentication success. Updating SecurityContextHolder to contain: authResult);}//将认证成功后的对象保存到 SecurityContext中SecurityContextHolder.getContext().setAuthentication(authResult);//处理 remember-me属性this.rememberMeServices.loginSuccess(request, response, authResult);if (this.eventPublisher ! null) {this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));}//认证成功后页面跳转this.successHandler.onAuthenticationSuccess(request, response, authResult);} 上边的核心代码是下边这一行 attemptAuthentication方法的作用是获取Authentication对象其实就是对应的认证过程 attemptAuthentication 方法在子类UsernamePasswordAuthenticationFilter 中实现的。 attemptAuthentication 方法代码如下
//认证逻辑
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {//如果我们设置了该认证请求只能以post方式提交且当前请求不是post请求表示当前请求不符合//认证要求直接抛出异常认证失败if (this.postOnly !request.getMethod().equals(POST)) {throw new AuthenticationServiceException(Authentication method not supported: request.getMethod());} else {//执行到这里表示开始执行认证逻辑//从请求中获取用户名和密码String username this.obtainUsername(request);String password this.obtainPassword(request);if (username null) {username ;}if (password null) {password ;}username username.trim();//将用户名和密码包装成 UsernamePasswordAuthenticationToken 对象UsernamePasswordAuthenticationToken authRequest new UsernamePasswordAuthenticationToken(username, password);//设置用户提交的信息到 UsernamePasswordAuthenticationToken 中this.setDetails(request, authRequest);//getAuthenticationManager()获取认证管理器//authenticate真正处理认证的方法return this.getAuthenticationManager().authenticate(authRequest);}} 1、
3、AuthenticationManager AuthenticationManager接口中就定义了一个方法authenticate方法用于处理认证的请求 AuthenticationManager 接口定义如下
public interface AuthenticationManager {//处理认证请求Authentication authenticate(Authentication authentication) throws AuthenticationException;} 在这里AuthenticationManager的默认实现是ProviderManager.而在ProviderManager的 authenticate方法中实现的操作是循环遍历成员变量ListAuthenticationProvider providers 。该providers中如果有一个AuthenticationProvider的supports函数返回true那么就会调 用该AuthenticationProvider的authenticate函数认证如果认证成功则整个认证过程结束。 如果不成功则继续使用下一个合适的AuthenticationProvider进行认证只要有一个认证 成功则为认证成功。 authenticate 方法定义如下 //执行认证逻辑
public Authentication authenticate(Authentication authentication)throws AuthenticationException {//获取 Authentication 对象的类型Class? extends Authentication toTest authentication.getClass();AuthenticationException lastException null;AuthenticationException parentException null;Authentication result null;Authentication parentResult null;boolean debug logger.isDebugEnabled();//getProviders()获取系统支持的各种认证方式如QQ、微信、微博等等for (AuthenticationProvider provider : getProviders()) {//判断当前的 provider认证处理器 是否支持当前请求的认证类型若不支持则跳过if (!provider.supports(toTest)) {continue;}if (debug) {logger.debug(Authentication attempt using provider.getClass().getName());}//执行到这里说明当前认证处理器支持当前请求的认证try {//执行认证操作result provider.authenticate(authentication);if (result ! null) {copyDetails(authentication, result);break;}}catch (AccountStatusException e) {//。。。。。省略 。。。。。}catch (InternalAuthenticationServiceException e) {//。。。。。省略 。。。。。}catch (AuthenticationException e) {//。。。。。省略 。。。。。}}//如果循环结束后还没找到支持当前请求的认证处理器provider 且父类不为空则//尝试调用父类的认证方法进行认证处理if (result null parent ! null) {// Allow the parent to try.try {result parentResult parent.authenticate(authentication);}catch (ProviderNotFoundException e) {//。。。。。省略 。。。。。}catch (AuthenticationException e) {//。。。。。省略 。。。。。}}//清空密码凭证if (result ! null) {if (eraseCredentialsAfterAuthentication (result instanceof CredentialsContainer)) {// Authentication is complete. Remove credentials and other secret data// from authentication((CredentialsContainer) result).eraseCredentials();}//if (parentResult null) {eventPublisher.publishAuthenticationSuccess(result);}return result;}// //异常处理if (lastException null) {lastException new ProviderNotFoundException(messages.getMessage(ProviderManager.providerNotFound,new Object[] { toTest.getName() },No AuthenticationProvider found for {0}));}//if (parentException null) {prepareException(lastException, authentication);}throw lastException;} 在上边的代码中我们重点看的是下边这一行 result provider.authenticate(authentication); 因为是用户认证所以这里authenticate方法走是AbstractUserDetailsAuthenticationProvider 类中的实现 AbstractUserDetailsAuthenticationProvider.authenticate 方法定义如下所示
//认证操作
public Authentication authenticate(Authentication authentication)throws AuthenticationException {Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,() - messages.getMessage(AbstractUserDetailsAuthenticationProvider.onlySupports,Only UsernamePasswordAuthenticationToken is supported));// 获取提交的账号String username (authentication.getPrincipal() null) ? NONE_PROVIDED: authentication.getName();//标记是否使用缓存默认是使用的先从缓存中查找提交的账号//若账号已经登录则缓存中应该boolean cacheWasUsed true;//根据账号名称从缓存中查找账号若缓存中不存在该账号则需要认证UserDetails user this.userCache.getUserFromCache(username);if (user null) {//若缓存中不存在该账号,没有缓存cacheWasUsed false;try {//账号认证user retrieveUser(username,(UsernamePasswordAuthenticationToken) authentication);}catch (UsernameNotFoundException notFound) {//。。。。。省略 。。。。。}Assert.notNull(user,retrieveUser returned null - a violation of the interface contract);}try {//如果账号存在即账号认证成功则这里就开始密码认证//密码校验前的前置检查检查账号是否过期、是否锁定等preAuthenticationChecks.check(user);//密码校验//user: 数据库中的数据//authentication: 表单提交的数据additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);}catch (AuthenticationException exception) {//。。。。。省略 。。。。。}//检查凭证是否过期postAuthenticationChecks.check(user);//将用户保存到缓存中if (!cacheWasUsed) {this.userCache.putUserInCache(user);}Object principalToReturn user;if (forcePrincipalAsString) {principalToReturn user.getUsername();}return createSuccessAuthentication(principalToReturn, authentication, user);
}//创建具体的 Authentication 对象
protected Authentication createSuccessAuthentication(Object principal,Authentication authentication, UserDetails user) {// user.getAuthorities()返回用户的权限UsernamePasswordAuthenticationToken result new UsernamePasswordAuthenticationToken(principal, authentication.getCredentials(),authoritiesMapper.mapAuthorities(user.getAuthorities()));result.setDetails(authentication.getDetails());return result;}密码前置校验如下图所示 然后进入到retrieveUser方法中retrieveUser和additionalAuthenticationChecks 方法 具体的实现是DaoAuthenticationProvider 类中实现的如下所示
Overrideprotected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)throws AuthenticationException {prepareTimingAttackProtection();try {// getUserDetailsService会获取到我们自定义的UserServiceImpl对象也就是会走我们自定义的认证方法了UserDetails loadedUser this.getUserDetailsService().loadUserByUsername(username);if (loadedUser null) {throw new InternalAuthenticationServiceException(UserDetailsService returned null, which is an interface contract violation);}return loadedUser;}catch (UsernameNotFoundException ex) {//。。。。。省略 。。。。。}catch (InternalAuthenticationServiceException ex) {//。。。。。省略 。。。。。}catch (Exception ex) {//。。。。。省略 。。。。。}}//具体的密码校验逻辑
protected void additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication)throws AuthenticationException {//凭证为空即密码没传进来则直接抛出异常if (authentication.getCredentials() null) {logger.debug(Authentication failed: no credentials provided);throw new BadCredentialsException(messages.getMessage(AbstractUserDetailsAuthenticationProvider.badCredentials,Bad credentials));}//获取表单提交的密码String presentedPassword authentication.getCredentials().toString();//拿表单提交的密码与数据库中的密码进行匹配若匹配失败则抛出异常if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {logger.debug(Authentication failed: password does not match stored value);throw new BadCredentialsException(messages.getMessage(AbstractUserDetailsAuthenticationProvider.badCredentials,Bad credentials));}}