SpringSceurity实现短信验证码功能的示例代码

下面我将详细讲解如何使用Spring Security实现短信验证码功能。这里假设你已经有了一个基于Spring Security的Web应用程序,现在要添加短信验证码功能。

准备工作

在开始实现之前需要进行一些准备工作:

1.添加Spring Security支持短信验证码功能的依赖;

pom.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>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-servlet</artifactId>
    <version>${spring.security.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

2.配置短信验证码发送的相关信息;

可以使用Spring的@Configuration注解创建一个Bean来配置短信验证码发送的相关信息,例如短信网关地址、短信模板等。

实现

下面将分步骤来实现Spring Security中的短信验证码功能。

步骤1:创建一个用于发送短信验证码的服务

可以使用Spring的@Component注解创建一个短信发送服务的Bean。

@Component
public class SmsCodeSender {

    @Autowired
    private SmsCodeProperties smsCodeProperties;

    private final static Logger logger = LoggerFactory.getLogger(SmsCodeSender.class);

    public void sendSmsCode(String mobile, String code) {
        // 发送短信验证码的代码
    }
}

步骤2:编写一个生成短信验证码的过滤器

可以使用Spring的OncePerRequestFilter来过滤需要生成短信验证码的请求。

public class SmsCodeFilter extends OncePerRequestFilter {

    @Autowired
    private SmsCodeSender smsCodeSender;

    @Autowired
    private SmsCodeProperties smsCodeProperties;

    private AntPathMatcher pathMatcher = new AntPathMatcher();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if ("POST".equalsIgnoreCase(request.getMethod()) && pathMatcher.match("/login/mobile", request.getServletPath())) {
            try {
                validate(new ServletWebRequest(request));
            } catch (ValidationException e) {
                // 验证失败,返回错误信息
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("验证码错误或已过期!");
            }
        } else {
            filterChain.doFilter(request, response);
        }
    }

    private void validate(ServletWebRequest request) {
        String mobile = request.getParameter("mobile");
        String smsCode = request.getParameter("smsCode");

        // 从Session中获取短信验证码
        String codeInSession = (String) request.getRequest().getSession().getAttribute(SmsCodeController.SESSION_KEY_SMS_CODE + mobile);

        if (StringUtils.isBlank(smsCode)) {
            throw new ValidationException("验证码不能为空!");
        }

        if (codeInSession == null) {
            throw new ValidationException("验证码不存在!");
        }

        if (!StringUtils.equals(codeInSession, smsCode)) {
            throw new ValidationException("验证码不正确!");
        }

        request.getRequest().getSession().removeAttribute(SmsCodeController.SESSION_KEY_SMS_CODE + mobile);
    }

}

步骤3:配置短信验证码过滤器

需要在Spring Security过滤器链中添加自定义的短信验证码过滤器,以便拦截需要验证短信验证码的请求。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SmsCodeFilter smsCodeFilter;

    // ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/login")
                .successForwardUrl("/index")
                .and()
                .authorizeRequests().antMatchers("/login/**").permitAll()
                .anyRequest().authenticated()
                .and().csrf().disable();
    }
}

步骤4:生成和发送短信验证码

可以使用Spring的@Controller注解创建一个控制器,在控制器中生成和发送短信验证码。

@Controller
@Slf4j
public class SmsCodeController {

    public static final String SESSION_KEY_SMS_CODE = "SESSION_KEY_SMS_CODE:";

    @Autowired
    private SmsCodeSender smsCodeSender;

    @Autowired
    private SmsCodeProperties smsCodeProperties;

    @PostMapping("/code/sms")
    @ResponseBody
    public JsonResponse createSmsCode(HttpServletRequest request, @RequestParam("mobile") String mobile) throws ServletRequestBindingException {
        if (!MobileUtils.isMobile(mobile)) {
            return JsonResponse.error("手机号码格式不正确!");
        }

        // 生成短信验证码
        String code = RandomStringUtils.randomNumeric(6);
        String key = SESSION_KEY_SMS_CODE + mobile;

        request.getSession().setAttribute(key, code);
        request.getSession().setMaxInactiveInterval(smsCodeProperties.getExpireTime());

        // 发送短信验证码
        smsCodeSender.sendSmsCode(mobile, code);
        log.info("手机号 [" + mobile + "] 短信验证码 [" + code + "] 已发送");

        return JsonResponse.ok("短信验证码已发送!");
    }

}

示例1

这个示例的目的是显示一个用于获取验证码的按钮,并添加一个JavaScript函数来调用后端的短信列表。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<form id="login-form" action="/login" method="post" style="padding: 10px;">
    <input type="text" name="mobile" placeholder="电话号码"/>
    <input type="text" name="smsCode" placeholder="短信验证码"/>
    <button id="sms-button" type="button">获取短信验证码</button>
    <button type="submit">登录</button>
</form>

<script>
    $(document).ready(function () {
        $('#sms-button').click(function () {
            $.ajax({
                url: '/code/sms',
                data: {
                    mobile: $('input[name="mobile"]').val()
                },
                success: function (data) {
                    alert(data.message);
                },
                error: function (e) {
                    alert("发生错误!");
                }
            });
        });
    });
</script>
</body>
</html>

在上面的代码中,#sms-button是用于获取验证码的按钮的ID。当用户单击该按钮时,JavaScript将会以GET方法调用/code/sms地址。后端的SmsCodeController将会生成和发送短信验证码。

示例2

一个简单的启用短信验证码功能的Spring Security配置可以是这样的:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SmsCodeFilter smsCodeFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers("/", "/login**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/login")
                .successHandler(new LoginSuccessHandler())
                .failureHandler(new LoginFailureHandler())
                .and()
                .logout()
                .logoutUrl("/logout")
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID")
                .permitAll()
                .and()
                .csrf().disable();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

在上面的示例代码中,除了添加SmsCodeFilter过滤器之外,其他内容都和普通的Spring Security配置一样。例如,/admin/**路径要求用户有ADMIN角色,所有其他请求都需要用户被验证(即登录)。LoginSuccessHandlerLoginFailureHandler是登录成功或失败时将要执行的一些逻辑。关闭CSRF保护是为了使示例变得更加简单,可以在实际项目中开启它。

结论

Spring Security提供了一个灵活和可扩展的框架,可以轻松实现短信验证码功能。使用短信验证码可以提高Web应用程序的安全性,同时也为用户提供更加便捷的登录方式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSceurity实现短信验证码功能的示例代码 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Spring存储与读取Bean对象方法

    下面是关于”Spring存储与读取Bean对象方法”的完整攻略。 1. 前置知识 在学习本文之前,建议先掌握以下知识: Java基础 Spring基础 Spring IOC 2. 存储Bean对象到Spring容器 在Spring框架中,可以通过ApplicationContext接口来加载Bean对象,也可以将Bean对象保存到容器中。具体实现方式有两种:…

    Java 2023年5月26日
    00
  • J2ME/J2EE实现用户登录交互 实现代码

    J2ME和J2EE都是Java程序开发的重要领域,其中J2EE是面向企业级应用开发的,而J2ME则是面向移动设备的小型Java平台。在开发应用程序时,用户登录交互是不可或缺的一个功能,本文将讲解如何使用J2ME和J2EE实现用户登录交互,并提供两个示例。 J2ME实现用户登录交互 J2ME的用户界面开发常用的框架是MIDP(Mobile Informatio…

    Java 2023年6月15日
    00
  • SpringBoot @PostMapping接收HTTP请求的流数据问题

    要实现SpringBoot @PostMapping接收HTTP请求的流数据,需要遵循以下步骤: 在Controller中添加接口,使用@PostMapping注解,并使用@RequestBody注解请求参数; 创建一个封装流数据的Java对象,并使用@RequestBody注解接收请求参数; 在请求头中添加Content-Type字段,值为applicat…

    Java 2023年6月3日
    00
  • Linux下PHP+MYSQL+APACHE配置过程 (摘)第1/2页

    针对“Linux下PHP+MYSQL+APACHE配置过程”这一话题,我会提供一个完整的攻略,并在过程中举两个实例说明,内容如下: Linux下PHP+MYSQL+APACHE配置过程 安装apache 在Linux系统下,Apache是一款非常流行的Web服务器软件,可以通过以下步骤进行安装: 更新包管理器 sudo apt update 安装apache…

    Java 2023年6月2日
    00
  • Spring Boot 项目启动失败的解决方案

    Spring Boot是一个非常流行的Java框架,但在启动Spring Boot项目时,可能会遇到各种问题。以下是详细讲解Spring Boot项目启动失败的解决方案的完整攻略: 检查依赖 在启动Spring Boot项目之前,我们需要检查项目的依赖是否正确。我们可以使用以下命令来检查项目的依赖: mvn dependency:tree 该命令将显示项目的…

    Java 2023年5月15日
    00
  • 浅谈Maven Wrapper

    关于如何使用 Maven Wrapper,我这里提供一份完整攻略,包含以下内容: 什么是 Maven Wrapper Maven Wrapper 是 Maven 内置的一个小型 Maven 版本管理工具,是 Maven 3.5.0 版本中引入的新特性。它的主要作用是帮助使用者对 Maven 进行版本控制,防止出现版本不一致的问题。使用 Maven Wrapp…

    Java 2023年6月2日
    00
  • 详解Java中native方法的使用

    详解Java中native方法的使用 什么是native方法 在Java中,native方法是指使用C、C++等非Java语言实现的方法,通常用于Java程序中需要与底层操作系统或硬件等交互的场景,比如操作系统中调用一些API,访问硬件等。 使用native方法 在Java中使用native方法需要以下步骤: 声明native方法,以告诉编译器该方法的实现不…

    Java 2023年5月26日
    00
  • 关于maven打包出错的解决方案

    下面是讲解“关于maven打包出错的解决方案”的完整攻略。 问题描述 在使用 Maven 打包过程中,有时会出现打包失败的情况,比如无法找到依赖库、编译错误等等,这给开发者带来困扰,下面将介绍几种解决方案。 解决方案 方案一:清理本地仓库 执行以下命令清理本地 Maven 仓库中的缓存以及无用依赖,重新下载所需的依赖。 mvn clean 方案二:检查依赖参…

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