为了美观和更好的用户体验,我们需要修改登录页面和服务端代码,系统默认只会返回用户无法找到UsernameNotFoundException这一错误,自定义的目的就是希望能区分用户未注册还是账号或密码错误。
所以要加入自己的loginFailureHandler
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
return daoAuthenticationProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//放行静态资源
.antMatchers("/login", "/oauth/**", "/check_token").permitAll()
.anyRequest()
.authenticated()
.and()
//允许form登录
.formLogin()
.loginPage("/login").permitAll()
//配置登录成功、失败Handler返回自定义错误信息
.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler)
.and().logout().permitAll()
.and().csrf().disable();
}
@Component
public class LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {
/**
* 拦截 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 错误类型
*/
@Override
public void onAuthenticationFailure
(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
/* 默认:执行重定向或转发到defaultfailureurl(如果设置),Otherw返回401错误代码 */
//super.onAuthenticationFailure(request,response,exception)
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
JSONObject res = new JSONObject();
res.put("code", 401);
if (exception instanceof UsernameNotFoundException) {
res.put("msg", "用户不存在");
writer.write(res.toJSONString());
}
if (exception instanceof BadCredentialsException) {
res.put("msg", "用户名或密码错误");
writer.write(res.toJSONString());
}
writer.flush();
writer.close();
}
}
登录页请求
let formData = new FormData();
//参数
formData.append("username", this.username);
formData.append("password", this.password);
axios.post("/login", formData)
.then(res => {
if (401 === res.data.code) {
alert(res.data.msg);
} else if (200 === res.data.code) {
window.location.href = res.data.targetUrl;
}
}).catch(error => {
alert("系统错误");
});
另外,登录成功后原来的代码采用的是重定向的方式返回的,但是如果我们前端用ajax去请求,重定向的时候就会报错,所以我们还需要改造LoginSuccessHandler
@Component
public class LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private RequestCache requestCache = new HttpSessionRequestCache();
@Override
public void onAuthenticationSuccess
(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
SavedRequest savedRequest = requestCache.getRequest(request, response);
if (savedRequest == null) {
//直接输入 http://www.avanty.com:8766/login 不带重定向的地址 则可以考虑跳转到本系统的首页 或者自定义提示信息
return;
}
//清除属性
clearAuthenticationAttributes(request);
// Use the DefaultSavedRequest URL
String targetUrl = savedRequest.getRedirectUrl();
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
JSONObject res = new JSONObject();
res.put("code", 200);
res.put("msg", "认证成功");
res.put("targetUrl", targetUrl);
writer.write(res.toJSONString());
writer.flush();
writer.close();
}
public void setRequestCache(RequestCache requestCache) {
this.requestCache = requestCache;
}
}
服务端只返回重定向的地址,由前端自己去跳转
至此,认证服务端差不多就改造完毕了。