一:自定义认证

1.自定义认证需要实现 spring security 提供的 UserDetailService 接口

  1. public interface UserDetailsService {
  2. UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
  3. }

2.接口的 loadUserByUsername 方法返回一个 UserDetails 接口。

  1. public interface UserDetails extends Serializable {
  2. /**
  3. *获取用户包含的权限,返回权限集合,权限是一个继承了GrantedAuthority的对象;
  4. */
  5. Collection<? extends GrantedAuthority> getAuthorities();
  6. /**
  7. *密码
  8. */
  9. String getPassword();
  10. /**
  11. * 用户名
  12. */
  13. String getUsername();
  14. /**
  15. * 用于判断账户是否未过期,未过期返回true反之返回false;
  16. */
  17. boolean isAccountNonExpired();
  18. /**
  19. * 判断账户是否未锁定;
  20. */
  21. boolean isAccountNonLocked();
  22. /**
  23. * 判断用户凭证是否没过期,即密码是否未过期;
  24. */
  25. boolean isCredentialsNonExpired();
  26. /**
  27. * 判断用户是否可用
  28. */
  29. boolean isEnabled();
  30. }
  1. 自定义实现 UserDetails /UserDetailsService

    1. @Configuration
    2. public class MyUserDetailService implements UserDetailsService {
    3. @Autowired
    4. private PasswordEncoder passwordEncoder;
    5. @Override
    6. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    7. // 模拟数据库获取用户数据 getUserByName(username);
    8. String password = "123456";
    9. // 需要加密
    10. password = passwordEncoder.encode(password);
    11. boolean enabled = true;
    12. boolean accountNonExpired = true;
    13. boolean credentialsNonExpired = true;
    14. boolean accountNonLocked = true;
    15. // 模拟权限
    16. List<GrantedAuthority> admin = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
    17. // 返回 security 提供的 UserDetails 接口实现类 User
    18. return new User(username, password, enabled,
    19. accountNonExpired, credentialsNonExpired,
    20. accountNonLocked, admin);
    21. }
    22. }
  2. MySecurityConfig 配置注入加密 Bean

    1. @Configuration
    2. public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    3. @Bean
    4. public PasswordEncoder passwordEncoder() {
    5. return new BCryptPasswordEncoder();
    6. }

    二: 替换默认登录页面

    在配置文件中新增:

    1. @Override
    2. protected void configure(HttpSecurity http) throws Exception {
    3. // httpBasic 认证方式
    4. // http.httpBasic()
    5. // 表单方式登录
    6. http.formLogin()
    7. // 自定义登录页
    8. .loginPage("login.html")
    9. // 登录接口
    10. .loginProcessingUrl("/login")
    11. .and()
    12. // 授权配置
    13. .authorizeRequests()
    14. // 放开 login.html的请求
    15. .antMatchers("/login.html").permitAll()
    16. // 所有请求
    17. .anyRequest()
    18. // 都需要认证
    19. .authenticated();
    20. }

.loginPage(“/login.html”)指定了跳转到登录页面的请求URL,.loginProcessingUrl(“/login”)对应登录页面form表单的action=”/login”,.antMatchers(“/login.html”).permitAll()表示跳转到登录页面的请求不被拦截,否则会进入无限循环。

三: 处理成功和失败

Spring Security有一套默认的处理登录成功和失败的方法:当用户登录成功时,页面会跳转会引发登录的请求,比如在未登录的情况下访问http://localhost:8080/hello,页面会跳转到登录页,登录成功后再跳转回来;登录失败时则是跳转到Spring Security默认的错误提示页面。下面我们通过一些自定义配置来替换这套默认的处理机制。

1.自定义登录成功逻辑

要改变默认的处理成功逻辑很简单,只需要实现org.springframework.security.web.authentication.AuthenticationSuccessHandler接口的onAuthenticationSuccess方法即可:

  1. @Component
  2. public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {
  3. @Autowired
  4. private ObjectMapper mapper;
  5. @Override
  6. public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
  7. Authentication authentication) throws IOException {
  8. response.setContentType("application/json;charset=utf-8");
  9. response.getWriter().write(mapper.writeValueAsString(authentication));
  10. }
  11. }
  1. 可以重定向跳转到index 接口:
  1. @Component
  2. public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {
  3. @Autowired
  4. private ObjectMapper mapper;
  5. /** 跳转重定向 */
  6. private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
  7. @Override
  8. public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
  9. Authentication authentication) throws IOException {
  10. redirectStrategy.sendRedirect(request, response, "/index");
  11. }
  12. }
  1. @RequestMapping("/index")
  2. public Object index(){
  3. /** spring security 提供的上下文获取用户信息 */
  4. return SecurityContextHolder.getContext().getAuthentication();
  5. }

2.自定义登录失败逻辑

和自定义登录成功处理逻辑类似,自定义登录失败处理逻辑需要实现org.springframework.security.web.authentication.AuthenticationFailureHandler的onAuthenticationFailure方法:

  1. @Component
  2. public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {、
  3. @Autowired
  4. private ObjectMapper mapper;
  5. @Override
  6. public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
  7. AuthenticationException exception) throws IOException {
  8. // AuthenticationException 有很多实现类,不同的登录失败原因对应不同的异常
  9. // 此处可以根据异常信息,对应返回友好的提示信息、账户密码错误、用户已禁用等
  10. response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
  11. response.setContentType("application/json;charset=utf-8");
  12. response.getWriter().write(mapper.writeValueAsString(exception.getMessage()));
  13. }
  14. }

同样,配置类需要新增:

  1. @Autowired
  2. private MyAuthenticationFailureHandler authenticationFailureHandler;
  3. .......
  4. http.formLogin()
  5. // 自定义登录页
  6. .loginPage("/login.html")
  7. // 登录接口
  8. .loginProcessingUrl("/login")
  9. // 处理登录成功
  10. .successHandler(authenticationSucessHandler)
  11. // 处理登录失败
  12. .failureHandler(authenticationFailureHandler)
  13. ........