背景:支持其他登录方案例如证书登录
放行/login,自定义登录验证方式。
一、模板
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login")
.permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("javaboy").password("{noop}123").roles("admin").build());
provider.setUserDetailsService(manager);
return new ProviderManager(provider);
}
}
1、首先在登录放行中,添加 /login 接口,这是我即将自定义的第二个登录接口。
2、提供一个 AuthenticationManager 实例。创建 AuthenticationManager 实例时,还需要提供一个 DaoAuthenticationProvider,大家知道,用户密码的校验工作在这个类里边完成,并为 DaoAuthenticationProvider 配置一个 UserDetailsService 实例,该实体提供了用户数据源。
接下来提供一个登录接口:
@RestController
public class LoginController {
@Autowired
AuthenticationManager authenticationManager;
@PostMapping("/login2")
public String login2(String username, String password, HttpServletRequest req) {
try {
Authentication token = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
SecurityContextHolder.getContext().setAuthentication(token);
return "success";
} catch (Exception e) {
e.printStackTrace();
}
return "failed";
}
}
在登录接口中,传入用户名密码等参数,然后将用户名密码等参数封装成一个 UsernamePasswordAuthenticationToken 对象,最后调用 AuthenticationManager#authenticate 方法进行验证,验证成功后会返回一个认证后的 Authentication 对象,再手动把该 Authentication 对象存入 SecurityContextHolder 中。
二、自定义流程登录
通过自定义provider、自定义token 实现自定义的登录验证机制,这样比较灵活,两个都可以拓展。
1、注册自定义provider
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
SM2AuthenticationProvider sm2AuthenticationProvider = new SM2AuthenticationProvider();
sm2AuthenticationProvider.setUserDetailsService(userDetailsService);
auth.authenticationProvider(sm2AuthenticationProvider);
}
2、provider 自定义 ,实现 implements AuthenticationProvider 接口
重写 supports、authenticate 方法,自定义的逻辑代码写在 authenticate 方法中,该方法最后返回一个认证通过的自定义的token
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SM2AuthenticationToken sm2AuthenticationToken = (SM2AuthenticationToken) authentication;
UserDetails user = userDetailsService.loadUserByUsername((String) sm2AuthenticationToken.getPrincipal());;
LoginUser loginUser = (LoginUser) user;
.....
.....
SM2AuthenticationToken result = new SM2AuthenticationToken(user,user.getPassword(), user.getAuthorities());
return result;
}
@Override
public boolean supports(Class<?> aClass) {
return SM2AuthenticationToken.class.isAssignableFrom(aClass);
}
3、token自定义:继承extends AbstractAuthenticationToken ,可以根据需要拓展属性
4、实现验证
@Resource
private AuthenticationManager authenticationManager;
Authentication authentication = authenticationManager.authenticate(new SM2AuthenticationToken(username, password));
这样就完成验证流程。