现在有这么一个需求,客户端登录验证失败之后显示两种错误信息--"用户名不存在"或者"账号密码错误",但是spring Security好像并没有返回错误信息的类,所以需要我们自己从request域中去获取错误信息,首先我们要设置验证失败后的返回地址。
http.formLogin() //自定义自己编写的登陆页面
.loginPage("/login.html") //登陆页面设置
.loginProcessingUrl("/user/login") //登陆访问路径
.defaultSuccessUrl("/") //登陆成功后跳转路径
.failureUrl("/user/fail")//注意这里用请求转发,不要重定向
.permitAll()
.and().authorizeRequests()
.antMatchers("/user/**",
"/swagger-ui.html", "/v2/**", "/swagger-resources/**", "/webjars/springfox-swagger-ui/**")
.permitAll()//不拦截的路径
.antMatchers("/school/**").hasAuthority("admin")
// .antMatchers("/test/findAll").hasAnyAuthority("addUser,findAll")
// .antMatchers("/test/hello").hasRole("admin")
// .antMatchers("/test/hello").hasAnyRole("admin")
.anyRequest().authenticated()
.and().csrf().disable(); //关闭csrf的保护
然后我们在失败请求中利用request 来获取错误信息,所有的错误信息都会保存至"SPRING_SECURITY_LAST_EXCEPTION"中。
@ResponseBody
@RequestMapping("fail")
public ResultInfo loginFail(HttpServletRequest request , HttpServletResponse response){
//获取security的异常错误信息
AuthenticationException exception =
(AuthenticationException)request.getSession().getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
String msg = exception.getMessage();
System.out.println(msg);
return new ResultInfo("error!" , msg);
}
但是我们发现无论怎么抛出异常,最终都会显示“Bad credentials”,异常处理代码如下:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//调用usersMapper方法,根据用户名查询数据库
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username",username);
User user = userMapper.selectOne(wrapper);
//判断
if(user==null){//数据库没有数据,认证失败
throw new UsernameNotFoundException("用户名不存在!");
}
//手动设置了role,也可以通过数据库查询获取
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRole()); //配置角色
return new org.springframework.security.core.userdetails.User(user.getUsername(),
new BCryptPasswordEncoder().encode(user.getPassword()),auths);
}
此处详细处理方法参考http://t.csdn.cn/pnZhx
我这里用的是方法一
@Override
public UserDetails loadUserByUsername(String username) throws BadCredentialsException {
//调用usersMapper方法,根据用户名查询数据库
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username",username);
User user = userMapper.selectOne(wrapper);
//判断
if(user==null){//数据库没有数据,认证失败
throw new BadCredentialsException("用户名不存在!");
}
//手动设置了role,也可以通过数据库查询获取
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRole()); //配置角色
return new org.springframework.security.core.userdetails.User(user.getUsername(),
new BCryptPasswordEncoder().encode(user.getPassword()),auths);
}
问题解决。
注:有时候会出现返回值乱码的问题,原因是因为security的拦截器会默认将自己的拦截器放在第一位,而在SpringMVC中编码拦截器必须放在第一位。解决方法:在security的拦截器前加上编码拦截器
@Override
protected void configure(HttpSecurity http) throws Exception {
//添加转码
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceEncoding(true);
http.addFilterBefore(encodingFilter, CsrfFilter.class);
//配置没有权限访问跳转自定义页面
http.exceptionHandling().accessDeniedPage("/403.html");
http.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login.html")
.permitAll();
http.formLogin() //自定义自己编写的登陆页面
.loginPage("/login.html") //登陆页面设置
.loginProcessingUrl("/user/login") //登陆访问路径
.defaultSuccessUrl("/") //登陆成功后跳转路径
.failureUrl("/user/fail")
.permitAll()
.and().authorizeRequests()
.antMatchers("/user/**",
"/swagger-ui.html", "/v2/**", "/swagger-resources/**", "/webjars/springfox-swagger-ui/**")
.permitAll()//不拦截的路径
.antMatchers("/school/**").hasAuthority("admin")
// .antMatchers("/test/findAll").hasAnyAuthority("addUser,findAll")
// .antMatchers("/test/hello").hasRole("admin")
// .antMatchers("/test/hello").hasAnyRole("admin")
.anyRequest().authenticated()
.and().csrf().disable(); //关闭csrf的保护
}