授权方式提供者,判断授权有效性,用户有效性,在判断用户是否有效性,它依赖于UserDetailsService实例,开发人员可以自定义UserDetailsService的实现。
@Component @Slf4j public class LindAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @Autowired UserDetailsService userDetailsService; @Autowired private PasswordEncoder passwordEncoder; /** * 校验密码有效性. * * @param userDetails . * @param authentication . * @throws AuthenticationException . */ @Override 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")); } } /** * 获取用户. * * @param username . * @param authentication . * @return * @throws AuthenticationException . */ @Override protected UserDetails retrieveUser( String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { UserDetails loadedUser = userDetailsService.loadUserByUsername(username); if (loadedUser == null) { throw new InternalAuthenticationServiceException( "UserDetailsService returned null, which is an interface contract violation"); } return loadedUser; } }
授权过滤器,你可以自定义它,并把它添加到默认过滤器前或者后去执行,主要用来到授权的持久化,它可以从请求上下文中获取你的user,password等信息,然后去判断它是否符合规则,最后通过authenticate方法去授权。默认的 UsernamePasswordAuthenticationFilter
过滤器,主要判断请求方式是否为post,并且对username和password进行了默认值的处理,总之,在这个过滤器里不会涉及到具体业务。
public class LindUserNameAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public LindUserNameAuthenticationFilter() { super(new AntPathRequestMatcher("/login", "GET")); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { String username = request.getParameter("username"); String password = request.getParameter("password"); if (username == null) { throw new InternalAuthenticationServiceException("Failed to get the username"); } if (password == null) { throw new InternalAuthenticationServiceException("Failed to get the password"); } UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password); authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); return this.getAuthenticationManager().authenticate(authRequest); } }
这是一个接口,有默认的实现方式,一般的,我们需要根据业务去重新实现它,比如从你的用户表获取当前授权的用户信息,你需要在UserDetialsService实现类里对用户表进行读取操作;它一般会在AuthenticationProvider里的retrieveUser方法中被使用,这就像面向对象里的模板方法模式一样,springSecurity把检验的步骤设计好了,咱们开发只要根据规则去实现具体细节就好。
@Component public class MyUserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { // mock代码,正常应该从数据库读取 User user = new User(name, passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("read,ROLE_USER"));//设置权限和角色 return user; } }
springSecurity源码:https://github.com/spring-projects/spring-security