Spring Security – 自定义登录
1 使用formLogin()
http
.formLogin()
.loginPage("/myLogin") // 自定义登录页面
.loginProcessingUrl("/doLogin") // 自定义登录接口
.permitAll();
2 自定义登录过滤器
SpringSecurity 默认使用的是 UsernamePasswordAuthenticationFilter 过滤器,我们可以实现 AbstractAuthenticationProcessingFilter 类来自定义登录逻辑。
public class CustomLoginFilter extends AbstractAuthenticationProcessingFilter {
//private static final String defaultFilterProcessesUrl = "/login";
public CustomLoginFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String method = request.getMethod();
// 仅使用POST方法提交
if(!"POST".equalsIgnoreCase(method)){
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
// 从Session中取出验证码
String verify = (String) request.getSession().getAttribute("verify");
// 从请求中获取验证码
String code = request.getParameter("code");
// 检查验证码
checkCode(code,verify);
// 从请求中获取 用户名及命名
String username = request.getParameter("username");
String password = request.getParameter("password");
username = username==null?"":username.trim();
password = password==null?"":password.trim();
// 生成 username+password 形式的 token
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
// 设置token详细信息
authenticationToken.setDetails(authenticationDetailsSource.buildDetails(request));
// 交给内部 AuthenticationManager 去认证,并返回 Authentication
return this.getAuthenticationManager().authenticate(authenticationToken);
}
private void checkCode(String code,String verify){
if(code==null || verify==null || "".equals(code) || verify.equalsIgnoreCase(code)){
throw new AuthenticationServiceException("验证码错误:"+code);
}
}
}
实现 AuthenticationFailureHandler 接口,用于返回认证成功信息
public class LoginAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
onAuthenticationSuccess(request, response, authentication);
chain.doFilter(request,response);
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
HashMap<String, Object> map = new HashMap<>();
map.put("code",200);
map.put("msg","登陆成功");
//map.put("data",authentication.getDetails());
PrintWriter out = response.getWriter();
out.write(map.toString());
out.flush();
out.close();
}
}
实现 AuthenticationFailureHandler 接口返回 认证失败信息
public class LoginAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
HashMap<String, Object> map = new HashMap<>();
map.put("code",400);
if (exception instanceof LockedException) {
map.put("msg","账户被锁定,请联系管理员!");
} else if (exception instanceof CredentialsExpiredException) {
map.put("msg","密码过期,请联系管理员!");
} else if (exception instanceof AccountExpiredException) {
map.put("msg","账户过期,请联系管理员!");
} else if (exception instanceof DisabledException) {
map.put("msg","账户被禁用,请联系管理员!");
} else if (exception instanceof BadCredentialsException) {
map.put("msg","用户名或者密码输入错误,请重新输入!");
}else {
map.put("msg",exception.getMessage());
}
out.write(map.toString());
out.flush();
out.close();
}
}
在SpringSecurity配置类中配置:
authenticationManagerBean()是WebSecurityConfigurerAdapter 中内置的,直接调用即可
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Autowired
private LoginAuthenticationSuccessHandler loginAuthenticationSuccessHandler;
@Autowired
private LoginAuthenticationFailureHandler loginAuthenticationFailureHandler;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login","/login/doLogin","/css/**","/js/**","/images/**")
.permitAll()
.anyRequest()
.authenticated();
// 将自定义的过滤器添加进去
http.addFilterAt(customLoginFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public CustomLoginFilter customLoginFilter() throws Exception {
CustomLoginFilter customLoginFilter = new CustomLoginFilter("/login/doLogin");
customLoginFilter.setAuthenticationSuccessHandler(loginAuthenticationSuccessHandler);
customLoginFilter.setAuthenticationFailureHandler(loginAuthenticationFailureHandler);
customLoginFilter.setAuthenticationManager(authenticationManagerBean());
return customLoginFilter;
}
}
参考:
spring-security权限控制详解 .
2091

被折叠的 条评论
为什么被折叠?



