springsecurity 实现手机验证码登录完整流程
时间: 2023-08-12 19:03:16 浏览: 88
Spring Security 实现短信验证码登录功能
Spring Security 实现手机验证码登录的完整流程如下:
1. 添加相关依赖
首先,需要在项目中添加 Spring Security 和 Spring Boot Starter Web 的依赖。
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
```
2. 配置 Spring Security
在 Spring Security 的配置类中,需要进行以下配置:
- 配置忽略静态资源
- 配置登录页面和登录处理接口
- 配置登录成功后的跳转页面
- 配置用户认证和授权方式
```java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login", "/login/sendCode").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login/authenticate")
.successHandler(customAuthenticationSuccessHandler)
.permitAll()
.and()
.logout()
.permitAll()
.and()
.csrf()
.disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}
}
```
3. 自定义用户认证和授权
需要实现 `UserDetailsService` 接口,根据手机号码查询用户信息,然后实现 `UserDetails` 接口返回用户信息。
```java
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
User user = userRepository.findByMobile(mobile);
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
return new CustomUserDetails(user);
}
}
```
实现 `UserDetails` 接口,返回用户信息。
```java
public class CustomUserDetails implements UserDetails {
private User user;
public CustomUserDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptyList();
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getMobile();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
```
4. 实现发送验证码和校验验证码
在登录页面中,需要添加一个发送验证码的按钮,点击后通过 Ajax 请求发送验证码到用户手机上。
```javascript
function sendCode() {
$.ajax({
type: 'post',
url: '/login/sendCode',
data: {mobile: $('#mobile').val()},
success: function(result) {
if (result.code === 0) {
alert('验证码发送成功');
} else {
alert(result.message);
}
},
error: function() {
alert('系统错误');
}
});
}
```
服务端接收到请求后,生成一个 6 位数的随机数作为验证码,并保存到 Redis 中,设置过期时间为 5 分钟。
```java
public class SmsCodeSender {
private static final String SMS_CODE_PREFIX = "sms_code_";
public void send(String mobile) {
String code = RandomStringUtils.randomNumeric(6);
System.out.println("给手机号 " + mobile + " 发送验证码 " + code);
RedisUtils.set(SMS_CODE_PREFIX + mobile, code, 5, TimeUnit.MINUTES);
}
}
```
在登录处理接口中,需要校验用户输入的验证码是否与 Redis 中保存的验证码一致。
```java
@Controller
public class LoginController {
@Autowired
private SmsCodeSender smsCodeSender;
@PostMapping("/login/sendCode")
@ResponseBody
public Result sendCode(String mobile) {
smsCodeSender.send(mobile);
return Result.success();
}
@PostMapping("/login/authenticate")
public String login(String mobile, String code, HttpServletRequest request) {
String smsCode = RedisUtils.get(SmsCodeSender.SMS_CODE_PREFIX + mobile);
if (StringUtils.isBlank(smsCode)) {
throw new BadCredentialsException("验证码已过期,请重新发送");
}
if (!smsCode.equals(code)) {
throw new BadCredentialsException("验证码不正确");
}
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(mobile, null);
Authentication authentication = AuthenticationManagerBuilderUtils.getAuthenticationManager().authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
return "redirect:/index";
}
@GetMapping("/login")
public String loginPage() {
return "login";
}
}
```
5. 自定义登录成功处理器
在登录成功后,需要跳转到指定页面并显示用户信息。
```java
@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.sendRedirect("/index");
}
}
```
6. 完成
至此,Spring Security 实现手机验证码登录的完整流程就完成了。
阅读全文