怎么用Springboot整合SpringSecurity实现账号密码和手机验证码登陆功能

发布时间:2021-07-29 19:11:21 作者:chen
来源:亿速云 阅读:463

怎么用Springboot整合SpringSecurity实现账号密码和手机验证码登陆功能

在现代Web应用中,用户认证是一个非常重要的功能。Spring Security 是一个功能强大且高度可定制的安全框架,能够为Spring应用提供全面的安全服务。本文将详细介绍如何使用Spring Boot整合Spring Security,实现账号密码和手机验证码两种登录方式。

1. 环境准备

在开始之前,确保你已经具备以下环境:

2. 创建Spring Boot项目

首先,使用Spring Initializr创建一个新的Spring Boot项目。选择以下依赖:

生成项目后,导入到你的IDE中。

3. 配置Spring Security

3.1 添加依赖

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>

3.2 配置Redis

application.properties中配置Redis连接信息:

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.timeout=2000

3.3 配置Spring Security

创建一个配置类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());
    }
}

3.4 实现UserDetailsService

创建一个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()
        );
    }
}

4. 实现手机验证码登录

4.1 创建验证码实体

创建一个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);
    }
}

4.2 生成验证码

创建一个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();
    }
}

4.3 存储验证码

创建一个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);
    }
}

4.4 实现手机验证码认证

创建一个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);
    }
}

4.5 创建控制器

创建一个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();
    }
}

5. 测试

启动应用后,你可以通过以下步骤测试:

  1. 访问/sms/code接口,发送验证码到手机。
  2. 访问/sms/login接口,使用手机号和验证码登录。

6. 总结

通过本文的介绍,你已经学会了如何使用Spring Boot整合Spring Security,实现账号密码和手机验证码两种登录方式。Spring Security提供了强大的扩展能力,你可以根据实际需求进一步定制和扩展认证流程。希望本文对你有所帮助,祝你在Spring Security的学习和使用中取得更多进展!

推荐阅读:
  1. ssh账号密码登陆
  2. django实现账号密码验证登陆功能

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring springboot springsecurity

上一篇:Linux常见的问题有哪些

下一篇:如何调试Dreamview的启动问题

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》