登录页面如何实现手机验证码
时间: 2023-11-04 15:06:12 浏览: 74
要实现手机验证码功能的登录页面,可以按照以下步骤进行:
1. 用户输入手机号码:在登录页面中添加一个手机号码输入框,要求用户输入手机号。
2. 生成验证码:后端服务器收到用户提交的手机号后,通过短信服务商的接口生成一个随机的验证码,并将该验证码与用户手机号绑定。
3. 发送验证码:将生成的验证码通过短信服务商的接口发送到用户的手机号上。
4. 验证码校验:用户收到验证码后,在登录页面中添加一个验证码输入框,要求用户输入收到的验证码。
5. 提交校验:用户在验证码输入框中输入完毕后,点击提交按钮。
6. 后端校验:后端服务器接收到用户提交的验证码后,与之前绑定的手机号对应的验证码进行比对,判断是否匹配。
7. 登录成功或失败:根据验证码校验的结果,如果匹配成功,则允许用户继续登录;如果匹配失败,则提示用户重新输入正确的验证码。
需要注意的是,要实现手机验证码功能,你需要获取一个可靠的短信服务商的接口,并将其集成到你的后端服务器中。此外,为了防止滥用,你可能还需要设置一些限制,比如每个手机号码一天只能请求一定次数的验证码。
相关问题
springsecurity实现手机验证码登录
Spring Security可以很方便地实现手机验证码登录,步骤如下:
1. 添加spring-security-web和spring-security-config依赖。
```xml
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
</dependency>
```
2. 创建一个实现UserDetailsService接口的类,该类用于根据不同的用户名加载用户信息。
```java
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.selectByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
return new UserPrincipal(user);
}
}
```
3. 创建一个实现AuthenticationProvider接口的类,该类用于验证用户的手机号和验证码是否正确。
```java
@Service
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
String mobile = authenticationToken.getPrincipal().toString();
String code = authenticationToken.getCredentials().toString();
String redisCode = redisTemplate.opsForValue().get(SmsCodeAuthenticationFilter.REDIS_SMS_CODE_KEY_PREFIX + mobile);
if (StringUtils.isBlank(redisCode)) {
throw new BadCredentialsException("验证码不存在或已过期");
}
if (!StringUtils.equals(code, redisCode)) {
throw new BadCredentialsException("验证码不正确");
}
UserDetails userDetails = new UserPrincipal(new User(mobile, "", Collections.emptyList()));
return new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
}
}
```
4. 创建一个实现AuthenticationFilter接口的类,该类用于处理短信验证码登录请求。
```java
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";
public static final String REDIS_SMS_CODE_KEY_PREFIX = "SMS_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("不支持的请求方式: " + request.getMethod());
}
String mobile = obtainMobile(request);
String code = obtainCode(request);
if (StringUtils.isBlank(mobile)) {
throw new UsernameNotFoundException("手机号不能为空");
}
if (StringUtils.isBlank(code)) {
throw new BadCredentialsException("验证码不能为空");
}
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) {
this.mobileParameter = mobileParameter;
}
public void setCodeParameter(String codeParameter) {
this.codeParameter = codeParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
public final String getMobileParameter() {
return mobileParameter;
}
public final String getCodeParameter() {
return codeParameter;
}
}
```
5. 在WebSecurityConfigurerAdapter的子类中进行配置。
```java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private SmsCodeAuthenticationProvider smsCodeAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login/mobile").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").defaultSuccessURL("/home").permitAll()
.and()
.logout().logoutUrl("/logout").permitAll()
.and()
.addFilterBefore(smsCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(smsCodeAuthenticationProvider)
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SmsCodeAuthenticationFilter smsCodeAuthenticationFilter() {
SmsCodeAuthenticationFilter filter = new SmsCodeAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\": 0, \"message\": \"登录成功\"}");
out.flush();
out.close();
});
filter.setAuthenticationFailureHandler((request, response, exception) -> {
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\": 1, \"message\": \"" + exception.getMessage() + "\"}");
out.flush();
out.close();
});
return filter;
}
}
```
6. 在前端页面中添加短信验证码登录的表单。
```html
<form action="/login/mobile" method="post">
<div>
<label>手机号:</label>
<input type="text" name="mobile" />
</div>
<div>
<label>验证码:</label>
<input type="text" name="code" />
<button type="button" onclick="sendSmsCode()">发送验证码</button>
</div>
<div>
<button type="submit">登录</button>
</div>
</form>
```
7. 在后端控制器中添加发送短信验证码的接口。
```java
@RestController
public class SmsCodeController {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@GetMapping("/sms/code")
public void sendSmsCode(String mobile) {
String code = RandomStringUtils.randomNumeric(6);
redisTemplate.opsForValue().set(SmsCodeAuthenticationFilter.REDIS_SMS_CODE_KEY_PREFIX + mobile, code, 5, TimeUnit.MINUTES);
// 发送短信验证码
}
}
```
以上就是使用Spring Security实现手机验证码登录的全部步骤。
使用springboot实现手机验证码code登录
可以通过以下步骤使用springboot实现手机验证码登录:
1. 集成Spring Security依赖
在`pom.xml`文件中添加以下依赖:
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
```
2. 实现UserDetailsService接口
创建一个类实现`UserDetailsService`接口,并在其中实现从数据库中获取用户信息的逻辑。例如:
```
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String phoneNumber) throws UsernameNotFoundException {
User user = userRepository.findByPhoneNumber(phoneNumber);
if (user == null) {
throw new UsernameNotFoundException("User not found with phoneNumber: " + phoneNumber);
}
return new org.springframework.security.core.userdetails.User(user.getPhoneNumber(), user.getPassword(),
new ArrayList<>());
}
}
```
3. 配置Spring Security
在`application.properties`文件中配置Spring Security相关属性:
```
# 禁用CSRF保护,因为我们将使用手机验证码进行登录
security.enable-csrf=false
# 配置登录页面和处理登录请求的控制器
spring.security.loginProcessingUrl = /login
spring.security.loginPage = /login.html
```
4. 创建登录页面
创建一个名为`login.html`的登录页面,包含一个表单,用于输入手机号和验证码。例如:
```
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form action="/login" method="post">
<div>
<label for="phoneNumber">Phone Number:</label>
<input type="text" id="phoneNumber" name="phoneNumber" required>
</div>
<div>
<label for="code">Code:</label>
<input type="text" id="code" name="code" required>
<button type="button" id="sendCode">Send Code</button>
</div>
<button type="submit">Login</button>
</form>
<script>
// 发送验证码的逻辑
document.getElementById("sendCode").addEventListener("click", function() {
var phoneNumber = document.getElementById("phoneNumber").value;
// 调用后端API发送验证码
// ...
});
</script>
</body>
</html>
```
5. 实现发送验证码API
创建一个控制器,用于处理发送验证码的API请求。例如:
```
@RestController
public class SMSController {
@PostMapping("/sendCode")
public ResponseEntity<?> sendCode(@RequestParam("phoneNumber") String phoneNumber) {
// 调用发送短信验证码的服务
// ...
return ResponseEntity.ok().build();
}
}
```
6. 实现登录API
创建一个控制器,用于处理登录API请求。在该控制器中,使用`AuthenticationManager`和`TokenBasedRememberMeServices`来实现登录逻辑。例如:
```
@RestController
public class LoginController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenBasedRememberMeServices rememberMeServices;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestParam("phoneNumber") String phoneNumber, @RequestParam("code") String code,
HttpServletRequest request, HttpServletResponse response) {
// 校验验证码是否正确
// ...
// 创建一个UsernamePasswordAuthenticationToken,以便交给AuthenticationManager进行验证
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(phoneNumber, code);
// 让AuthenticationManager进行验证,并返回一个Authentication对象
Authentication authentication = authenticationManager.authenticate(token);
// 让TokenBasedRememberMeServices进行处理,并返回一个RememberMeAuthenticationToken对象
RememberMeAuthenticationToken rememberMeToken = rememberMeServices
.autoLogin(request, response);
// 将两个Authentication对象合并成一个
Authentication mergedAuthentication = new PreAuthenticatedAuthenticationToken(
authentication.getPrincipal(), authentication.getCredentials(),
Stream.concat(authentication.getAuthorities().stream(), rememberMeToken.getAuthorities().stream())
.collect(Collectors.toList()));
// 在SecurityContextHolder中存储合并后的Authentication对象
SecurityContextHolder.getContext().setAuthentication(mergedAuthentication);
// 登录成功,返回一个空响应
return ResponseEntity.ok().build();
}
}
```
这样,我们就实现了使用springboot实现手机验证码登录。需要注意的是,该代码仅为示例,实际场景中可能需要根据具体需求进行修改。