下面就为您详细讲解“Spring Security Oauth2.0 实现短信验证码登录示例”的完整攻略。
准备工作
- 搭建Spring Boot环境
- 添加Spring Security依赖
- 添加Spring Security Oauth2依赖
- 添加MySQL数据库及驱动依赖
- 创建用户表、客户端表、验证码表
示例1:实现短信验证码登录
- 自定义继承于
AbstractUserDetailsAuthenticationProvider
的短信验证码验证器SmsCodeAuthenticationProvider
,实现自定义的验证逻辑。
@Component
public class SmsCodeAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
// 校验用户信息
}
@Override
protected UserDetails retrieveUser(String mobile, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
UserDetails userDetails = userDetailsService.loadUserByUsername(mobile);
// 校验短信验证码
return userDetails;
}
}
- 自定义实现
AuthenticationFilter
的短信验证码登录认证过滤器SmsCodeAuthenticationFilter
,处理短信验证码登录请求,生成UsernamePasswordAuthenticationToken
传递给SmsCodeAuthenticationProvider
。
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public SmsCodeAuthenticationFilter() {
super(new AntPathRequestMatcher("/login/sms", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String mobile = request.getParameter("mobile");
String smsCode = request.getParameter("smsCode");
SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile, smsCode);
setDetails(request, authRequest);
AuthenticationManager authenticationManager = getAuthenticationManager();
return authenticationManager.authenticate(authRequest);
}
protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
}
- 在Spring Security的配置类中,注册
SmsCodeAuthenticationFilter
和SmsCodeAuthenticationProvider
。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SmsCodeAuthenticationProvider smsCodeAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login/sms").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(smsCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/")
.permitAll()
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(smsCodeAuthenticationProvider);
}
@Bean
public SmsCodeAuthenticationFilter smsCodeAuthenticationFilter() throws Exception {
SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter();
smsCodeAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/"));
smsCodeAuthenticationFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"));
return smsCodeAuthenticationFilter;
}
}
- 在前端页面中添加短信验证码登录的链接和表单。
<a href="#" onclick="sendSmsCode()">获取验证码</a>
<form id="smsLoginForm" action="/login/sms" method="post">
<input type="text" name="mobile" placeholder="请输入手机号" required />
<input type="text" name="smsCode" placeholder="请输入验证码" required />
<input type="submit" value="提交" />
</form>
示例2:实现短信验证码登录和密码登录的多重验证
在上面添加短信验证码登录的基础上,我们可以进一步实现多重验证的需求,例如需要同时验证密码和短信验证码。
- 在Spring Security的配置类中,注册一个新的
AuthenticationProvider
,用于处理多重验证的逻辑。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(smsCodeAuthenticationProvider)
.authenticationProvider(new MultiAuthenticationProvider(Arrays.asList(smsCodeAuthenticationProvider, daoAuthenticationProvider())));
}
private DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
return daoAuthenticationProvider;
}
- 在自定义
MultiAuthenticationProvider
中按需调用已注册的AuthenticationProvider
进行验证。
public class MultiAuthenticationProvider implements AuthenticationProvider {
private List<AuthenticationProvider> providers;
public MultiAuthenticationProvider(List<AuthenticationProvider> providers) {
this.providers = providers;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
AuthenticationException lastException = null;
for (AuthenticationProvider provider : providers) {
try {
return provider.authenticate(authentication);
} catch (AuthenticationException e) {
lastException = e;
}
}
throw lastException;
}
@Override
public boolean supports(Class<?> authentication) {
return providers.stream().anyMatch(p -> p.supports(authentication));
}
}
- 在前端页面中添加密码登录的表单。
<form id="passwordLoginForm" action="/login" method="post">
<input type="text" name="username" placeholder="请输入用户名" required />
<input type="password" name="password" placeholder="请输入密码" required />
<input type="submit" value="登录" />
</form>
- 在Spring Security的配置类中排除密码登录的请求地址。
http
.authorizeRequests()
.antMatchers("/login/sms").permitAll()
.antMatchers("/login").not().hasAnyAuthority(Authority.ADMIN.name(), Authority.USER.name())
.anyRequest().authenticated()
.and()
.addFilterBefore(smsCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/")
.permitAll()
.and()
.csrf().disable();
以上就是“Spring Security Oauth2.0 实现短信验证码登录示例”的完整攻略。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security Oauth2.0 实现短信验证码登录示例 - Python技术站