您好,登录后才能下订单哦!
在现代Web应用中,用户认证是一个非常重要的功能。Spring Security 是一个功能强大且高度可定制的安全框架,能够为Spring应用提供全面的安全服务。本文将详细介绍如何使用Spring Boot整合Spring Security,实现账号密码和手机验证码两种登录方式。
在开始之前,确保你已经具备以下环境:
首先,使用Spring Initializr创建一个新的Spring Boot项目。选择以下依赖:
生成项目后,导入到你的IDE中。
在pom.xml
中添加以下依赖:
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Spring Boot Starter Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
在application.properties
中配置Redis连接信息:
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.timeout=2000
创建一个配置类SecurityConfig
,继承WebSecurityConfigurerAdapter
,并重写configure
方法:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private SmsCodeAuthenticationProvider smsCodeAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login", "/sms/login", "/sms/code").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/home")
.permitAll()
.and()
.logout()
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(smsCodeAuthenticationProvider)
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
创建一个UserDetailsService
实现类,用于加载用户信息:
@Service
public class CustomUserDetailsService 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");
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
Collections.emptyList()
);
}
}
创建一个SmsCode
实体类,用于存储验证码信息:
@Data
public class SmsCode {
private String code;
private LocalDateTime expireTime;
public SmsCode(String code, int expireIn) {
this.code = code;
this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
}
public boolean isExpired() {
return LocalDateTime.now().isAfter(expireTime);
}
}
创建一个SmsCodeGenerator
类,用于生成验证码:
@Component
public class SmsCodeGenerator {
private static final String NUMBERS = "0123456789";
public String generate(int length) {
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(NUMBERS.charAt(random.nextInt(NUMBERS.length())));
}
return sb.toString();
}
}
创建一个SmsCodeService
类,用于存储和验证验证码:
@Service
public class SmsCodeService {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private SmsCodeGenerator smsCodeGenerator;
public void save(String phone, SmsCode smsCode) {
redisTemplate.opsForValue().set(phone, smsCode.getCode(), 300, TimeUnit.SECONDS);
}
public SmsCode get(String phone) {
String code = redisTemplate.opsForValue().get(phone);
if (code == null) {
return null;
}
return new SmsCode(code, 300);
}
public void remove(String phone) {
redisTemplate.delete(phone);
}
}
创建一个SmsCodeAuthenticationToken
类,用于封装手机号和验证码:
public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 1L;
private final Object principal;
public SmsCodeAuthenticationToken(String phone) {
super(null);
this.principal = phone;
setAuthenticated(false);
}
public SmsCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return this.principal;
}
}
创建一个SmsCodeAuthenticationProvider
类,用于验证手机号和验证码:
@Component
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
@Autowired
private SmsCodeService smsCodeService;
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String phone = (String) authentication.getPrincipal();
SmsCode smsCode = smsCodeService.get(phone);
if (smsCode == null || smsCode.isExpired()) {
throw new BadCredentialsException("Invalid sms code");
}
smsCodeService.remove(phone);
UserDetails userDetails = userDetailsService.loadUserByUsername(phone);
return new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
}
}
创建一个SmsCodeController
类,用于处理验证码请求和手机登录请求:
@RestController
public class SmsCodeController {
@Autowired
private SmsCodeService smsCodeService;
@Autowired
private SmsCodeGenerator smsCodeGenerator;
@PostMapping("/sms/code")
public ResponseEntity<?> sendSmsCode(@RequestParam String phone) {
String code = smsCodeGenerator.generate(6);
smsCodeService.save(phone, new SmsCode(code, 300));
// 这里可以调用短信服务发送验证码
return ResponseEntity.ok().build();
}
@PostMapping("/sms/login")
public ResponseEntity<?> smsLogin(@RequestParam String phone, @RequestParam String code) {
SmsCode smsCode = smsCodeService.get(phone);
if (smsCode == null || !smsCode.getCode().equals(code)) {
throw new BadCredentialsException("Invalid sms code");
}
smsCodeService.remove(phone);
// 这里可以返回JWT Token或其他认证信息
return ResponseEntity.ok().build();
}
}
启动应用后,你可以通过以下步骤测试:
/sms/code
接口,发送验证码到手机。/sms/login
接口,使用手机号和验证码登录。通过本文的介绍,你已经学会了如何使用Spring Boot整合Spring Security,实现账号密码和手机验证码两种登录方式。Spring Security提供了强大的扩展能力,你可以根据实际需求进一步定制和扩展认证流程。希望本文对你有所帮助,祝你在Spring Security的学习和使用中取得更多进展!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。