spring boot短信验证登录
时间: 2024-08-31 12:00:42 浏览: 60
Spring Boot短信验证码登录是一种常见的身份验证机制,它通常用于增强用户安全性,防止恶意登录尝试。在Spring Boot应用中实现这个功能,一般包括以下几个步骤:
1. **第三方库集成**:选择一个短信服务提供商,如阿里云短信、极光推送等,它们通常提供SDK供开发者集成。
2. **配置短信服务**:在`application.properties`或`application.yml`文件中配置短信服务的API密钥、发送号码等相关信息。
3. **创建验证码生成器**:使用随机数生成器和加密算法,生成一个暂时有效的验证码并保存到数据库。
4. **前端页面**:在登录表单中添加手机号输入框和发送验证码按钮,当用户点击后提交请求到后端。
5. **后端处理**:接收到请求后,从用户输入获取手机号,通过短信服务发送验证码到该手机。同时,在数据库设置一个过期时间。
6. **接收验证码验证**:用户输入收到的验证码,后端查询数据库验证是否匹配,并检查验证码是否已过期。
7. **安全登录**:如果验证码验证通过,创建Session或JWT令牌并返回给客户端,后续访问需要凭此验证权限。
相关问题
springsecurity实现短信验证码登录
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`,即可完成短信验证码登录。
spring oauth2 短信验证码登录
Spring OAuth2提供了一个框架,可以使我们很容易地实现短信验证码登录。下面是实现该功能的简单步骤:
1. 添加依赖
在pom.xml文件中添加以下依赖项:
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
```
2. 配置Security
在Spring Security配置文件中添加以下配置:
```
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.logout().permitAll();
}
}
```
这将启用Web安全性,并配置Spring Security以使用我们提供的用户详细信息服务和密码编码器。它还允许所有人访问OAuth2令牌端点(/oauth/token)。
3. 实现用户详细信息服务
我们需要实现UserDetailsService接口来从我们的数据库或其他数据源中获取用户详细信息。以下是一个示例:
```
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if(user == null){
throw new UsernameNotFoundException("User not found with username: " + username);
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
new ArrayList<>());
}
}
```
此服务返回Spring Security的UserDetails对象,该对象包含有关用户的详细信息。
4. 实现自定义的短信验证码登录过滤器
我们需要实现一个自定义的过滤器来处理短信验证码登录。以下是一个示例:
```
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_MOBILE_KEY = "mobile";
public static final String SPRING_SECURITY_FORM_CODE_KEY = "code";
private String mobileParameter = SPRING_SECURITY_FORM_MOBILE_KEY;
private String codeParameter = SPRING_SECURITY_FORM_CODE_KEY;
private boolean postOnly = true;
public SmsCodeAuthenticationFilter() {
super(new AntPathRequestMatcher("/login/mobile", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String mobile = obtainMobile(request);
String code = obtainCode(request);
if (mobile == null) {
mobile = "";
}
if (code == null) {
code = "";
}
mobile = mobile.trim();
SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile, code);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected String obtainMobile(HttpServletRequest request) {
return request.getParameter(mobileParameter);
}
protected String obtainCode(HttpServletRequest request) {
return request.getParameter(codeParameter);
}
protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
public void setMobileParameter(String mobileParameter) {
Assert.hasText(mobileParameter, "Mobile parameter must not be empty or null");
this.mobileParameter = mobileParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
public final String getMobileParameter() {
return mobileParameter;
}
public String getCodeParameter() {
return codeParameter;
}
public void setCodeParameter(String codeParameter) {
Assert.hasText(codeParameter, "Code parameter must not be empty or null");
this.codeParameter = codeParameter;
}
}
```
此过滤器将处理POST请求,其中包含用户的手机号码和短信验证码。它将创建一个SmsCodeAuthenticationToken对象,该对象将包含有关用户的信息。在这里,我们还可以设置其他详细信息,例如IP地址和请求的时间戳等。
5. 配置认证管理器
在Spring Security配置文件中添加以下配置:
```
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private SmsCodeAuthenticationProvider smsCodeAuthenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
auth.authenticationProvider(smsCodeAuthenticationProvider);
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/login/mobile").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.logout().permitAll();
http.addFilterBefore(smsCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public SmsCodeAuthenticationFilter smsCodeAuthenticationFilter() throws Exception {
SmsCodeAuthenticationFilter filter = new SmsCodeAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
@Bean
public SmsCodeAuthenticationProvider smsCodeAuthenticationProvider(){
return new SmsCodeAuthenticationProvider();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
```
这将配置我们的认证管理器,并告诉Spring Security使用我们自定义的SmsCodeAuthenticationProvider来验证短信验证码。我们还需要将自定义的SmsCodeAuthenticationFilter添加到过滤器链中。
6. 实现自定义的短信验证码认证提供程序
我们需要实现一个自定义的认证提供程序来验证短信验证码。以下是一个示例:
```
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
UserDetails userDetails = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
if(userDetails == null){
throw new InternalAuthenticationServiceException("无法获取用户信息");
}
SmsCode smsCode = (SmsCode) authenticationToken.getCredentials();
if(!smsCode.getCode().equals("123456")){
throw new BadCredentialsException("短信验证码不正确");
}
SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());
authenticationResult.setDetails(authenticationToken.getDetails());
return authenticationResult;
}
@Override
public boolean supports(Class<?> authentication) {
return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
}
}
```
此提供程序将验证提供的短信验证码,并返回一个已验证的SmsCodeAuthenticationToken对象。
最后,我们就可以使用短信验证码登录了。用户只需在登录页面上输入其手机号码和收到的短信验证码即可成功登录。