您现在的位置是:主页 > news > 餐饮网站建设网站/珠海seo关键词排名
餐饮网站建设网站/珠海seo关键词排名
admin2025/5/3 19:42:31【news】
简介餐饮网站建设网站,珠海seo关键词排名,做物流网站注意什么,自己做抽奖网站违法账号密码认证部分 进入认证过滤器doFilter方法: AbstractAuthenticationProcessingFilter.doFilter()/* * 判断当前filter是否可以处理当前请求,若不行,则交给下一个filter去处理。 * 踩坑:如果登陆接口 错误使用了GET方法 而…
账号密码认证部分
进入认证过滤器doFilter方法:
AbstractAuthenticationProcessingFilter.doFilter()
/*
* 判断当前filter是否可以处理当前请求,若不行,则交给下一个filter去处理。
* 踩坑:如果登陆接口 错误使用了GET方法 而不是POST方法
* 你就会惊喜的发现 attemptAuthentication 方法不执行 直接到下一个过滤器的authenticate方法
*/
if (!requiresAuthentication(request, response)) {chain.doFilter(request, response);return;
}
这里也可以实现UsernamePasswordAuthenticationFilter类 并重写attemptAuthentication方法
// doFilter方法里面 调用了子类(UsernamePasswordAuthenticationFilter)的方法
authResult = this.attemptAuthentication(request, response);
UsernamePasswordAuthenticationFilter attemptAuthentication方法的处理
// 认证请求的方式必须为POST
if (postOnly && !request.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}// 接下来 对账号密码为空的处理
username = username != null ? username : "";
username.trim()
.....// Authenticaiton类的实现类UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// 构造方法
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {super((Collection)null);this.principal = principal;this.credentials = credentials;this.setAuthenticated(false);
}// 构造器设置权限为null?super((Collection)null);
// 授权为false?this.setAuthenticated(false);// 这里是刚刚登陆过来,账号密码还没验证,所以这里需要放行// super: public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {if (authorities == null) {this.authorities = AuthorityUtils.NO_AUTHORITIES;} else {Iterator var2 = authorities.iterator();while(var2.hasNext()) {GrantedAuthority a = (GrantedAuthority)var2.next();Assert.notNull(a, "Authorities collection cannot contain any null elements");}this.authorities = Collections.unmodifiableList(new ArrayList(authorities));}}
// 现在回到attemptAuthentication方法:
return this.getAuthenticationManager().authenticate(authRequest);
this.getAuthenticationManager() 获取到ProviderManager类
ProviderManager.authenticate(authentication)方法做了什么?//全局变量 private List<AuthenticationProvider> providers;// 获取所有的providers 所以AuthenticationProvider类也是可以由我们重写Iterator var9 = this.getProviders().iterator();Authentication authResult = null;while(var9.hasNext()) {AuthenticationProvider provider = (AuthenticationProvider)var9.next();// 如果有支持当前token的 if (provider.supports(toTest)) {// 核心:调用处理 在authenticate方法里面进行密码校验authResult = provider.authenticate(authentication);}}// return authResult
这里我们再分析一下核心步骤: provider.authenticate(authentication);
// provider默认是调用AbstractUserDetailsAuthenticationProvider类的AbstractUserDetailsAuthenticationProvider.authenticate(Authentication authentication)
this.retrieveUser(username, (UsernamePasswordAuthenticationToken)authentication);
会去调用子类DaoAuthenticationProvider的retrieveUser方法
在retrieveUser方法里面会去调用这个我们最熟悉的方法:
userDetailsService.loadUserByUsername
将结果逐级返回后 至此 attemptAuthentication方法结束 , 别忘了这是在doFilter方法调用的,
回到doFilter里面:
// 最终认证成功后,会处理一些与session相关的方法(比如将认证信息存到session等操作)。
sessionStrategy.onAuthentication(authResult, request, response);
// doFilter 接下来的操作:
this.successfulAuthentication(request, response, chain, authResult);
最终认证成功后的相关回调方法,主要将当前的认证信息放到SecurityContextHolder中并调用成功处理器做相应的操作。
protected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response, FilterChain chain, Authentication authResult)throws IOException, ServletException {// 核心:将当前的认证信息放到SecurityContextHolder中SecurityContextHolder.getContext().setAuthentication(authResult);rememberMeServices.loginSuccess(request, response, authResult);// Fire eventif (this.eventPublisher != null) {eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));}// 调用成功处理器,可以自己实现AuthenticationSuccessHandler接口重写方法写自己的逻辑successHandler.onAuthenticationSuccess(request, response, authResult);
}
总结:
进入校验过滤器 doFilter方法
判断当前filter是否可以处理
默认调用子类 账号密码校验过滤器的attemptAuthentication方法
attemptAuthentication中校验是否为post请求,且对空账号密码进行处理
进入账号密码校验Token构造方法,构造方法会设置不需要权限 进行放行
(因为此时没有去匹配账号密码 必须放进去匹配一次)
调用provider.authenticate()
遍历并取出一个可以提供支持的provider并调用
调用retrieveUser方法
调用我们熟悉的 userDetails.loadUserByUsername
自定义账号密码校验规则
返回结果
结果做些session处理
结果成功处理: 存入securityContentHolder中
默认是使用threadLocal 实现的
token认证部分
实现BasicAuthenticationFilter 过滤器,在doFilterInternal方法进行校验
(token的储存是在账号密码认证成功后执行的 并将token返回至header)
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {public TokenAuthenticationFilter(AuthenticationManager authenticationManager) {super(authenticationManager);}public TokenAuthenticationFilter(AuthenticationManager authenticationManager, AuthenticationEntryPoint authenticationEntryPoint) {super(authenticationManager, authenticationEntryPoint);}@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws IOException, ServletException {String token = request.getHeader("Authorization");// 模拟从redis获取token : TokenUtils.getTokenList()if (!TokenUtils.getTokenList().contains(token)) {throw new RemoteException("token校验异常");}// 模拟 getUser by tokenUserVO userVO = new UserVO();userVO.setUsername("qiuhuanhen");userVO.setPassword("123456");UsernamePasswordAuthenticationToken authentication =new UsernamePasswordAuthenticationToken(userVO, "", new ArrayList<>());SecurityContextHolder.getContext().setAuthentication(authentication);chain.doFilter(request, response);}@Overrideprotected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {System.out.println("token 校验 成功");super.onSuccessfulAuthentication(request, response, authResult);}@Overrideprotected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {System.out.println("token 校验 失败");super.onUnsuccessfulAuthentication(request, response, failed);}
}
快速入门demo
写了个简单的登录认证demo
https://gitee.com/qiuhuanhen/springboot-security-login
注意事项: 见 README 文件