转载

SpringSecurity自定义AuthenticationProvider和AuthenticationFilter

AuthenticationProvider

  • 默认实现:DaoAuthenticationProvider

授权方式提供者,判断授权有效性,用户有效性,在判断用户是否有效性,它依赖于UserDetailsService实例,开发人员可以自定义UserDetailsService的实现。

  1. additionalAuthenticationChecks方法校验密码有效性
  2. retrieveUser方法根据用户名获取用户
@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;
  }
}

AuthenticationFilter

  • 默认实现:UsernamePasswordAuthenticationFilter

授权过滤器,你可以自定义它,并把它添加到默认过滤器前或者后去执行,主要用来到授权的持久化,它可以从请求上下文中获取你的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

这是一个接口,有默认的实现方式,一般的,我们需要根据业务去重新实现它,比如从你的用户表获取当前授权的用户信息,你需要在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;
  }
}

认证时执行的顺序

  1. LindUserNameAuthenticationFilter
  2. LindAuthenticationProvider.retrieveUser
  3. LindAuthenticationProvider.additionalAuthenticationChecks
  4. UserDetailsService
  5. Authentication

springSecurity源码:https://github.com/spring-projects/spring-security

原文  http://www.cnblogs.com/lori/p/10400564.html
正文到此结束
Loading...