一:自定义认证
1.自定义认证需要实现 spring security 提供的 UserDetailService 接口
public interface UserDetailsService {UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;}
2.接口的 loadUserByUsername 方法返回一个 UserDetails 接口。
public interface UserDetails extends Serializable {/***获取用户包含的权限,返回权限集合,权限是一个继承了GrantedAuthority的对象;*/Collection<? extends GrantedAuthority> getAuthorities();/***密码*/String getPassword();/*** 用户名*/String getUsername();/*** 用于判断账户是否未过期,未过期返回true反之返回false;*/boolean isAccountNonExpired();/*** 判断账户是否未锁定;*/boolean isAccountNonLocked();/*** 判断用户凭证是否没过期,即密码是否未过期;*/boolean isCredentialsNonExpired();/*** 判断用户是否可用*/boolean isEnabled();}
自定义实现 UserDetails /UserDetailsService
@Configurationpublic class MyUserDetailService implements UserDetailsService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 模拟数据库获取用户数据 getUserByName(username);String password = "123456";// 需要加密password = passwordEncoder.encode(password);boolean enabled = true;boolean accountNonExpired = true;boolean credentialsNonExpired = true;boolean accountNonLocked = true;// 模拟权限List<GrantedAuthority> admin = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");// 返回 security 提供的 UserDetails 接口实现类 Userreturn new User(username, password, enabled,accountNonExpired, credentialsNonExpired,accountNonLocked, admin);}}
MySecurityConfig 配置注入加密 Bean
@Configurationpublic class MySecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
二: 替换默认登录页面
在配置文件中新增:
@Overrideprotected void configure(HttpSecurity http) throws Exception {// httpBasic 认证方式// http.httpBasic()// 表单方式登录http.formLogin()// 自定义登录页.loginPage("login.html")// 登录接口.loginProcessingUrl("/login").and()// 授权配置.authorizeRequests()// 放开 login.html的请求.antMatchers("/login.html").permitAll()// 所有请求.anyRequest()// 都需要认证.authenticated();}
.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方法即可:
@Componentpublic class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {@Autowiredprivate ObjectMapper mapper;@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException {response.setContentType("application/json;charset=utf-8");response.getWriter().write(mapper.writeValueAsString(authentication));}}
可以重定向跳转到index 接口:
@Componentpublic class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {@Autowiredprivate ObjectMapper mapper;/** 跳转重定向 */private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException {redirectStrategy.sendRedirect(request, response, "/index");}}
@RequestMapping("/index")public Object index(){/** spring security 提供的上下文获取用户信息 */return SecurityContextHolder.getContext().getAuthentication();}
2.自定义登录失败逻辑
和自定义登录成功处理逻辑类似,自定义登录失败处理逻辑需要实现org.springframework.security.web.authentication.AuthenticationFailureHandler的onAuthenticationFailure方法:
@Componentpublic class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {、@Autowiredprivate ObjectMapper mapper;@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,AuthenticationException exception) throws IOException {// AuthenticationException 有很多实现类,不同的登录失败原因对应不同的异常// 此处可以根据异常信息,对应返回友好的提示信息、账户密码错误、用户已禁用等response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());response.setContentType("application/json;charset=utf-8");response.getWriter().write(mapper.writeValueAsString(exception.getMessage()));}}
同样,配置类需要新增:
@Autowiredprivate MyAuthenticationFailureHandler authenticationFailureHandler;.......http.formLogin()// 自定义登录页.loginPage("/login.html")// 登录接口.loginProcessingUrl("/login")// 处理登录成功.successHandler(authenticationSucessHandler)// 处理登录失败.failureHandler(authenticationFailureHandler)........
