通过查看UsernamePasswordAuthenticationFilter
获取用户名和密码的实现方法可以看到,默认只能获取form表单提供的数据,无法获得请求体中的数据。所以,要想获得请求体中的数据,需要自定义过滤器。
这里有两种方式获得用户名和密码
- 直接重写
obtainPassword
和obtainUsername
- 查看
attemptAuthentication
这个方法我们可以发现,用户名和密码是在这个方法里面获得并且使用的,因此我们可以直接重写这个方法。
1、编写UserAuthenticationFilter过滤器,继承UsernamePasswordAuthenticationFilter
@Slf4j
public class UserAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException {
try {
Employee employee = new ObjectMapper().readValue(req.getInputStream(), Employee.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(employee.getUsername(), employee.getPassword()));
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
}
2、IEmployeeService 接口继承UserDetailsService
public interface IEmployeeService extends IService<Employee>,UserDetailsService {
}
EmployeeServiceImpl实现类
这里只需要实现loadUserByUsername方法,验证用户是否存在、是否被禁用
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService{
@Autowired
EmployeeMapper employeeMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println(employeeMapper);
System.out.println(username);
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("username",username);
Employee employee = employeeMapper.selectOne(wrapper);
UserDetails userDetail = User.withUsername(username).password(employee.getPassword()).roles(username).build();
return userDetail;
}
}
3、编写UserLoginAuthenticationProvider,继承DaoAuthenticationProvider
通过继承DaoAuthenticationProvider,可以自定义用户密码验证并查看异常信息。
若不实现该类,抛出的异常信息会都变成Bad credentials
@Component
public class UserLoginAuthenticationProvider extends DaoAuthenticationProvider {
@Autowired
private UserDetailsServiceImpl detailsService;
@Autowired
private PasswordEncoder encoder;
/**
* 找到容器中的detailsService,并执行setUserDetailsService方法,完成赋值
*
* 必须要给UserDetailsService赋值,否则会出现UnsatisfiedDependencyException
*/
@Autowired
private void setDetailsService() {
setUserDetailsService(detailsService);
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
String presentedPassword = authentication.getCredentials().toString();
if (!encoder.matches(presentedPassword, userDetails.getPassword())) {
throw new BadCredentialsException(messages.getMessage("badCredentials", "用户密码错误"));
}
}
}
4、WebSecurityConfig 配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
IEmployeeService employeeService;
//注入AuthenticationManager,可能存在同名bean,
//配置文件中设置allow-bean-definition-overriding: true
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//使用DetailsService进行数据校验
auth.userDetailsService(employeeService).passwordEncoder(passwordEncoder());
//使用自定义的Provider,进行数据校验
// auth.authenticationProvider(loginAuthenticationProvider);
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
//重要,将UserAuthenticationFilter添加到容器
@Bean
public UserAuthenticationFilter userAuthenticationFilter() throws Exception {
UserAuthenticationFilter filter = new UserAuthenticationFilter();
//设置验证成功后的回调
filter.setAuthenticationSuccessHandler((request,response,authentication)->{
//响应成功状态码必须为200
response.setStatus(200);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("utf-8");
//将数据以json的形式返回给前台
response.getWriter().print(JSON.toJSONString(Result.success(null)));
});
//设置验证失败后的回调
filter.setAuthenticationFailureHandler((request, response, exception) ->{
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("utf-8");
//将数据以json的形式返回给前台
response.getWriter().print(JSON.toJSONString(Result.error("登录失败")));
});
//设置用户发起登陆请求时的url
filter.setFilterProcessesUrl("/employee/login");
filter.setAuthenticationManager(authenticationManager());
return filter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //屏蔽跨站请求
.authorizeRequests()
.anyRequest().permitAll()
.and()
.formLogin()
// .loginPage("employee/login")
.loginProcessingUrl("/employee/login")
.successForwardUrl("/success");
http.cors(); // 开启跨域
//添加自定义的过滤器
http.addFilterAt(userAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
5、axios.defaults.withCredentials=true//开启携带cookies
本文参考于:http://t.zoukankan.com/xlwq-p-13411575.html