Spring Security 实现多种登录方式(常规方式外的邮件、手机验证码登录)

yizhihongxing

Spring Security 实现多种登录方式攻略

Spring Security 作为一个强大的安全框架,支持多种登录方式,包括传统的用户名密码登录、第三方登录、手机短信验证码登录、邮件验证码登录等。本攻略将详细介绍如何使用 Spring Security 实现多种登录方式。

传统的用户名密码登录

传统的用户名密码登录是我们最常见的登录方式,主要涉及以下几个步骤:

  1. 配置 Spring Security 的安全配置类,并指定用户名密码登录接口的 URL。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password("{noop}admin")
                .roles("ADMIN");
    }
}
  1. 在 Spring Security 的配置类中,通过 formLogin() 方法启用表单登录,并指定登录页面的 URL。
.formLogin()
.loginPage("/login")
  1. 实现用户认证的逻辑。这里使用的是 InMemoryAuthentication 方式。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("admin")
            .password("{noop}admin")
            .roles("ADMIN");
}
  1. 实现用户授权的逻辑。
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/login").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/")
            .permitAll()
            .and()
            .logout()
            .permitAll();
}

手机短信验证码登录

手机短信验证码登录是一种比较流行的登录方式,相比传统的用户名密码登录,它更加方便快捷。手机短信验证码登录主要涉及以下几个步骤:

  1. 配置 Spring Security 的安全配置类,并指定手机号码登录接口的 URL。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .antMatchers("/sms/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/")
                .permitAll()
                .and()
                .logout()
                .permitAll()
                .and()
                .apply(smsAuthenticationConfig());
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password("{noop}admin")
                .roles("ADMIN");
    }

    private SmsAuthenticationConfig smsAuthenticationConfig() {
        SmsAuthenticationConfig authenticationConfig = new SmsAuthenticationConfig();
        authenticationConfig.setAuthenticationManager(authenticationManagerBean());
        authenticationConfig.setAuthenticationSuccessHandler(new SmsAuthenticationSuccessHandler());
        authenticationConfig.setAuthenticationFailureHandler(new SmsAuthenticationFailureHandler());
        return authenticationConfig;
    }
}
  1. 在 Spring Security 的配置类中,通过 apply() 方法配置短信验证码登录,指定短信验证码登录接口的 URL、短信验证码的有效期、短信验证码的长度等信息。
.apply(smsAuthenticationConfig());
  1. 实现短信验证码认证的逻辑。
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {

    private UserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;

        UserDetails user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());

        if (user == null) {
            throw new InternalAuthenticationServiceException("无法获取用户信息");
        }

        SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(user, user.getAuthorities());

        authenticationResult.setDetails(authenticationToken.getDetails());

        return authenticationResult;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

}
  1. 实现短信验证码授权的逻辑。
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private String mobileParameter = "mobile";
    private boolean postOnly = true;

    public SmsCodeAuthenticationFilter() {
        super(new AntPathRequestMatcher("/sms/login", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("认证方法不支持:" + request.getMethod());
        }

        String mobile = obtainMobile(request);

        if (mobile == null) {
            mobile = "";
        }

        mobile = mobile.trim();

        SmsCodeAuthenticationToken authenticationToken = new SmsCodeAuthenticationToken(mobile);

        setDetails(request, authenticationToken);

        return this.getAuthenticationManager().authenticate(authenticationToken);
    }

    protected String obtainMobile(HttpServletRequest request) {
        return request.getParameter(mobileParameter);
    }

    protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authenticationToken) {
        authenticationToken.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    public void setMobileParameter(String mobileParameter) {
        this.mobileParameter = mobileParameter;
    }

    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }

}

示例1:https://github.com/wangeditor/SpringSecurity/blob/main/demo-demo02/demo02-ssm/src/main/java/io/github/wangdaopeng/chapter2/controller/SmsCodeController.java

示例2:https://github.com/bfwg/springboot-jwt-starter/blob/master/src/main/java/com/bfwg/security/auth/SmsCodeAuthenticationProvider.java

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security 实现多种登录方式(常规方式外的邮件、手机验证码登录) - Python技术站

(2)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • SpringBoot设置动态定时任务的方法详解

    Spring Boot设置动态定时任务的方法详解 在Spring Boot中,我们可以使用Spring Task来实现定时任务。本文将详细讲解如何使用Spring Task设置动态定时任务,并提供两个示例。 1. 动态定时任务的概念 动态定时任务是指可以在运行时动态添加、修改和删除的定时任务。相比于静态定时任务,动态定时任务更加灵活和可扩展。 2. 动态定时…

    Java 2023年5月15日
    00
  • java 判断两个对象是否为同一个对象实例代码

    判断两个对象是否为同一个对象实例,在Java中可以通过以下两种方式实现: 方法一:使用“==”运算符 在Java中,“==”运算符用于比较两个对象的内存地址是否相等,如果相等,则说明这两个对象是同一个实例,反之则不是。因此,我们可以使用该运算符判断是否两个对象是同一个实例。 下面是示例代码: public class ObjectDemo { public …

    Java 2023年5月26日
    00
  • JAVA文件读写例题实现过程解析

    下面是关于JAVA文件读写例题实现过程解析的详细攻略: 1. 什么是文件读写 文件读写是指读取或者写入文件的一种操作。在Java中,通过File、FileReader、FileWriter类和BufferedReader、BufferedWriter类可以实现文件读写操作。 2. 文件读取的过程 文件读取的过程通常由以下几个步骤组成: 2.1 创建File对…

    Java 2023年5月19日
    00
  • Struts2的配置 struts.xml Action详解

    当我们用Struts2来开发Web应用程序时,需要进行相关的配置,其中最主要的配置文件就是struts.xml。在这个文件中,我们需要配置Action以及对应的Result、Interceptor等等。 下面是struts.xml的一个简单示例: <?xml version="1.0" encoding="UTF-8&qu…

    Java 2023年5月20日
    00
  • Atomic类的作用是什么?

    Atomic类是Java中原子性操作的一个封装类,可以用于无锁操作,避免多线程竞争问题。它提供了一组原子操作,具有以下三个特征:原子性、有序性和线程安全性。Atomic类对于高并发场景下的数据修改操作具有很大的帮助作用,可以提高程序的性能和稳定性。 在使用Atomic类时,常见的操作包括get获取当前值、set设置新值、compareAndSet(预期值,更…

    Java 2023年5月10日
    00
  • Java Zookeeper分布式分片算法超详细讲解流程

    Java Zookeeper分布式分片算法超详细讲解流程 简介 分片(Sharding)是一种数据库拆分技术,用于将整个数据库分成多个部分并存储在多个节点上,从而提高数据库的读写性能和可扩展性。Zookeeper是一个分布式的协调服务,也可以作为分布式分片算法的实现工具。本文将详细介绍Java Zookeeper分布式分片算法的实现过程。 什么是分布式分片 …

    Java 2023年5月20日
    00
  • java日期处理工具类

    首先我们来介绍Java日期处理工具类的相关知识。 Java日期时间相关类包括java.util.Date、java.util.Calendar、java.text.DateFormat等。其中,java.util.Date类常被使用,不过其具有不可修改性及兼容性问题。java.util.Calendar类可修改日期时间属性,但其对处理日期时间具有一定的局限性…

    Java 2023年5月20日
    00
  • 分享令人目瞪口呆的 Java 代码技巧

    现在来详细讲解“分享令人目瞪口呆的 Java 代码技巧”的完整攻略。 1. 提升代码的可读性 首先,我们来谈论一下如何提升 Java 代码的可读性。 代码缩进 好的代码缩进是提升代码可读性的一种重要手段。一般来说,对于每个代码块内的语句,都应当向右缩进一个相等数量的空格,以示其属于该代码块的范畴。例如: if (condition) { // … } e…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部