springsecurity实现短信验证码登录
时间: 2023-06-29 12:05:00 浏览: 171
Spring Security 支持多种认证方式,其中包括短信验证码登录。下面是一个简单的实现步骤:
1. 添加依赖
在 `pom.xml` 文件中添加以下依赖:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
```
2. 配置 Security
在 `application.yml` 文件中添加以下配置:
```yaml
spring:
security:
user:
name: admin
password: password
sms:
login:
url: /login/sms
parameter:
phone: phone
code: code
```
其中,`user` 节点用于配置默认的用户名和密码,`sms.login` 节点用于配置短信验证码登录的 URL 和参数名。
3. 实现短信验证码登录逻辑
创建一个实现 `UserDetailsService` 接口的类,用于通过手机号查询用户信息。在该类中实现 `loadUserByUsername` 方法,根据手机号查询用户信息并返回 `UserDetails` 对象。
```java
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundException {
User user = userService.getByPhone(phone);
if (user == null) {
throw new UsernameNotFoundException("手机号不存在");
}
return new User(user.getUsername(), user.getPassword(), user.getAuthorities());
}
}
```
创建一个实现 `AuthenticationProvider` 接口的类,用于处理短信验证码登录。在该类中实现 `authenticate` 方法,根据手机号和验证码验证用户信息并返回 `Authentication` 对象。
```java
@Component
public class SmsAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserService userService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String phone = authentication.getName();
String code = authentication.getCredentials().toString();
User user = userService.getByPhone(phone);
if (user == null) {
throw new UsernameNotFoundException("手机号不存在");
}
// 验证短信验证码
if (!"123456".equals(code)) {
throw new BadCredentialsException("短信验证码错误");
}
return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return SmsAuthenticationToken.class.isAssignableFrom(authentication);
}
}
```
其中,`SmsAuthenticationToken` 是自定义的认证对象,用于封装手机号和验证码信息。
4. 配置 Security 登录流程
在 Security 配置类中添加以下配置:
```java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private SmsAuthenticationProvider smsAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login/sms").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().disable()
.logout().disable()
.authenticationProvider(smsAuthenticationProvider)
.addFilterAfter(smsAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public SmsAuthenticationFilter smsAuthenticationFilter() throws Exception {
SmsAuthenticationFilter filter = new SmsAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/"));
filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"));
return filter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(smsAuthenticationProvider);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
```
其中,`SmsAuthenticationFilter` 是自定义的过滤器,用于处理短信验证码登录请求。在该过滤器中,获取手机号和验证码信息,封装为 `SmsAuthenticationToken` 对象并调用 `AuthenticationManager` 进行认证。
```java
public class SmsAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private String phoneParameter = "phone";
private String codeParameter = "code";
public SmsAuthenticationFilter() {
super(new AntPathRequestMatcher("/login/sms", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String phone = obtainPhone(request);
String code = obtainCode(request);
if (phone == null) {
phone = "";
}
if (code == null) {
code = "";
}
phone = phone.trim();
SmsAuthenticationToken authRequest = new SmsAuthenticationToken(phone, code);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
private String obtainPhone(HttpServletRequest request) {
return request.getParameter(phoneParameter);
}
private String obtainCode(HttpServletRequest request) {
return request.getParameter(codeParameter);
}
private void setDetails(HttpServletRequest request, SmsAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
public void setPhoneParameter(String phoneParameter) {
this.phoneParameter = phoneParameter;
}
public void setCodeParameter(String codeParameter) {
this.codeParameter = codeParameter;
}
}
```
至此,短信验证码登录已经实现。在登录页面中,用户输入手机号和验证码后,发送 POST 请求到 `/login/sms`,即可完成短信验证码登录。
阅读全文