实现短信验证码登录

31 篇文章 1 订阅
11 篇文章 0 订阅

注:此项目为微服务项目,前后端分离 vue+springboot+springcloud+layui
前端登录页面:
在这里插入图片描述
所使用的的pom.xml中的依赖:

         <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.5.16</version>
            <scope>compile</scope>
        </dependency>
        
		<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.1.41</version>
        </dependency>

        <!-- jwt依赖包 -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.6.0</version>
        </dependency>
		<!-- redis整合包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.2</version>
        </dependency>
        
		<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        
		  <!--Hutool Java工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.5.7</version>
        </dependency>

代码实现:

在工具类项目中创建AliyunSendMsgUtils工具类

package com.jq.msg;

import cn.hutool.json.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;

import java.util.Random;

public class AliyunSendMsgUtils {

    private static final String regionId = "cn-qingdao";

    private static final String accessKeyId = ""; //阿里云AccessKeyID   API的密钥

    private static final String accessSecret = ""; // 阿里云API的密钥Access Key Secret

    private static final String doMain = "dysmsapi.aliyuncs.com";    // 访问的阿里云域名

    private static final String version = "2017-05-25"; //版本号

    private static final String action = "SendSms"; //调用SendSms接口发送短信

    private static final String  signName="";  //短信签名名称

    private static final String  templateCode="";  //短信模板ID

    public static String sendMsg(String phone){
        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessSecret);
        IAcsClient client = new DefaultAcsClient(profile);

        CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain(doMain);
        request.setSysVersion(version);
        request.setSysAction(action);
        request.putQueryParameter("RegionId", regionId);
        request.putQueryParameter("PhoneNumbers", phone); //接收短信的手机号码
        request.putQueryParameter("SignName", signName);
        request.putQueryParameter("TemplateCode", templateCode);
        // 生成六位验证码
        String code = verificationCode();
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("code",code);
        request.putQueryParameter("TemplateParam",jsonObject.toString());//TemplateParam 短信模板变量对应的实际值
        try {
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
            return code;
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return null;
    }
    //生成随机6位验证码
    private static String  verificationCode(){
        String sources = "0123456789"; // 加上一些字母,就可以生成pc站的验证码了
        Random rand = new Random();
        StringBuffer flag = new StringBuffer();
        for (int j = 0; j < 6; j++)
        {
            flag.append(sources.charAt(rand.nextInt(9)) + "");
        }
        return flag.toString();
    }
}

创建JWTUtil 工具类


package com.jq.jwt;

import com.jq.result.ResultCode;
import com.jq.result.ResultObj;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
@PropertySource({"classpath:jwt.properties"})
public class JWTUtil {

    @Value("{user.jwtset.type}")
    private String type;

    @Value("{user.jwtset.alg}")
    private String alg;

    @Value("{user.jwtset.signing}")
    private String signing;




    public  String createToken(String  phone){
        // token由三部分组成:头部、有效负载,签名
        // 1.头部信息
        Map<String,Object> headerMap = new HashMap<String,Object>();
        headerMap.put("type",type);
        headerMap.put("alg",alg);

        // 2.有效负载
        Map<String,Object> payload = new HashMap<>();
        payload.put("phone",phone);
        payload.put("date",new Date());

        // 有效时间
        long timeMillis = System.currentTimeMillis();
        long endTime = timeMillis+6000000;

        // 3.签名
        String token = Jwts.builder().setHeader(headerMap)
                .setClaims(payload)
                .setExpiration(new Date(endTime))
                .signWith(SignatureAlgorithm.HS256, "signing")
                .compact();
        return token;
    }


    public static ResultObj verifyToken(String token) {
        try {
            Claims claims = Jwts.parser().setSigningKey("signing")
                    .parseClaimsJws(token)
                    .getBody();
            return ResultObj.success(claims);
        } catch (Exception e) {
            return ResultObj.error(ResultCode.TOKEN_ERROR);
        }
    }

    public static String getUsername(String token){
        try {
            Claims claims = Jwts.parser().setSigningKey("signing")
                    .parseClaimsJws(token)
                    .getBody();
            return (String) claims.get("username");
        } catch (Exception e) {
            return null;
        }
    }
}

创建统一返回值类

package com.jq.result;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultObj {

    // 状态码
    private Integer code;

    // 信息
    private String msg;

    // 数据
    private Object data;

    public ResultObj(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public static ResultObj success(){
        return new ResultObj(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg());
    }

    public static ResultObj success(Object data){
        return new ResultObj(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), data);
    }

    public static ResultObj error(ResultCode resultCode){
        return new ResultObj(resultCode.getCode(), resultCode.getMsg(),null);
    }


}

创建code码枚举类

package com.jq.result;


public enum ResultCode {

    SUCCESS(200,"操作成功"),
    ERROR(500,"操作失败"),
    USERNAME_PASSWORD_ISNULL(1001,"用户名或密码为空"),
    USER_NOEXIST(1002,"用户不存在"),
    PASSWORD_ERROR(1003,"密码错误"),
    TOKEN_ERROR(1004,"身份过期,请重新登录"),
    NO_PERMISSION(403,"没有权限访问该方法"),
    PHONE_NULL(1005,"手机号为空"),
    GET_CODE_ERROR(1006,"获取验证码失败"),
    PHONE_CODE_ISBULL(1007,"手机号码或验证码不能为空"),
    CODE_ERROR(1008,"验证码错误"),
    PHONE_CODE_TIMEOUT(1009,"手机号码不正确或验证码过期")
    ;

    private Integer code;
    private String msg;

    ResultCode(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

会员表 前端控制器代码:

package com.jq.member.controller;


import com.jq.jwt.JWTUtil;
import com.jq.msg.AliyunSendMsgUtils;
import com.jq.msg.RedisKeyUtils;
import com.jq.result.ResultCode;
import com.jq.result.ResultObj;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 会员表 前端控制器
 * </p>
 *
 * @author jq
 * @since 2021-04-06
 */
@RestController
@RequestMapping("/member")
@CrossOrigin//跨域
public class MemberController {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private JWTUtil jwtUtil;
    //获取验证码
    @GetMapping("{phone}")
    public ResultObj sendMsg(@PathVariable("phone") String phone){
            //判断手机号码为空
        if (StringUtils.isBlank(phone)){
            //返回手机号码为空的code
            return ResultObj.error(ResultCode.PHONE_NULL);
        }
        String code = AliyunSendMsgUtils.sendMsg(phone);
          //判断手机号码为空
        if (StringUtils.isBlank(code)){
            //返回获取验证码失败
            return ResultObj.error(ResultCode.GET_CODE_ERROR);
        }
        redisTemplate.opsForValue().set(RedisKeyUtils.getCodeKey(phone),code,3, TimeUnit.MINUTES);
        return ResultObj.success(code);
    }

    //登录
    @PostMapping("login")
    public ResultObj login(String phone,String code){
        //手机号码或验证码不能为空
        if(StringUtils.isBlank(phone) || StringUtils.isBlank(code)){
            //手机号码或验证码不能为空的code码
            return ResultObj.error(ResultCode.PHONE_CODE_ISBULL);
        }
        String code1 = (String) redisTemplate.opsForValue().get(RedisKeyUtils.getCodeKey(phone));
        //手机号码不正确或验证码过期
        if(StringUtils.isBlank(code1)){
            return ResultObj.error(ResultCode.PHONE_CODE_TIMEOUT);
        }
        if(!code.equals(code1)){
            //验证码错误
            return ResultObj.error(ResultCode.CODE_ERROR);
        }
         redisTemplate.delete(RedisKeyUtils.getCodeKey(phone));
        //生产token
        String token=jwtUtil.createToken(phone);
        return ResultObj.success(token);
    }
}


在这里插入图片描述

在resources\jwt.properties创建文件

user.jwtset.type=JWT
user.jwtset.alg=HS256
user.jwtset.signing=jq1223

前端Vue登录页面:

<template>
  <div>
    <div class="house-header">
      <div class="layui-container">
        <div class="house-nav">
          <span class="layui-breadcrumb" lay-separator="|">
          <a href="login.html">登录</a>
          <a href="">我的订单</a>
          <a href="">在线客服</a>
          </span>
          <span class="layui-breadcrumb house-breadcrumb-icon" lay-separator=" ">
            <a id="search"><i class="layui-icon layui-icon-house-find"></i></a>
            <a href="login.html"><i class="layui-icon layui-icon-username"></i></a>
            <a href="usershop.html"><i class="layui-icon layui-icon-house-shop"></i></a>
          </span>
        </div>
        <div class="house-banner layui-form">
          <a class="banner" href="index.html">
            <img src="../../../static/static/img/banner.png"  alt="家居商城">
          </a>
          <div class="layui-input-inline">
            <input type="text" placeholder="搜索好物"  class="layui-input"><i class="layui-icon layui-icon-house-find"></i>
          </div>
          <a class="shop" href="usershop.html"><i class="layui-icon layui-icon-house-shop"></i><span class="layui-badge">0</span></a>
        </div>
        <ul class="layui-nav close">
          <li class="layui-nav-item layui-this"><a href="index.html">首页</a></li>
          <li class="layui-nav-item"><a href="list.html">居家用品</a></li>
          <li class="layui-nav-item"><a href="list.html">小家电</a></li>
          <li class="layui-nav-item"><a href="list.html">洗护</a></li>
          <li class="layui-nav-item"><a href="list.html">厨具</a></li>
          <li class="layui-nav-item"><a href="list.html">日用品</a></li>
        </ul>
        <button id="switch">
          <span></span><span class="second"></span><span  class="third"></span>
        </button>
      </div>
    </div>
    <div class="layui-fulid" id="house-login" >
      <div class="layui-form">
        <p>手机号登录</p>
        <div class="layui-input-block login">
          <i class="layui-icon layui-icon-house-mobile"></i>
          <input type="number" required lay-verify="required"  placeholder="请输入手机号"  v-model="loginForm.phone"   @input="handerInput" class="layui-input">
        </div>
        <div class="layui-input-block getCode">
          <input type="number" required lay-verify="required"   placeholder="请输入短信验证码" v-model="loginForm.code"  class="layui-input">
          <button class="layui-btn" @click="getCode">获取验证码</button>
        </div>
        <button class="layui-btn"  lay-submit lay-filter="user-login" @click="login" @keyup.enter="keyDown">登录</button>
      </div>
    </div>

    <div class="house-footer">
      <div class="layui-container">
        <div class="intro">
          <span class="first"><i class="layui-icon layui-icon-house-shield"></i>7天无理由退换货</span>
          <span class="second"><i class="layui-icon layui-icon-house-car"></i>99元全场包邮</span>
          <span class="third"><i class="layui-icon layui-icon-house-diamond"></i>100%品质保证</span>
          <span class="last"><i class="layui-icon layui-icon-house-tel"></i>客服400-2888-966</span>
        </div>
        <div class="about">
      <span class="layui-breadcrumb" lay-separator="|">
        <a href="about.html">关于我们</a>
        <a href="about.html">帮助中心</a>
        <a href="about.html">售后服务</a>
        <a href="about.html">配送服务</a>
        <a href="about.html">关于货源</a>
      </span>
          <p>家居商城版权所有 &copy; 2012-2020</p>
        </div>
      </div>
    </div>

  </div>
</template>
<script>
  import {getCode,login} from "../../api/login/login";

  export default {
    name: "Login",
    data(){
      return {
        loginForm:{
          phone:"",
          code:""
        },
      }
    },
  methods:{


    //获取验证码
    getCode(){
      //判断手机号码是否正确
      if (this.loginForm.phone.length <= 0) {
        this.$message.error("请输入手机号");
      }else if (this.loginForm.phone.length != 11) {
        this.$message.error("请输入手机号为11位的手机号")
      }else if(!(/^1[3456789]\d{9}$/.test(this.loginForm.phone))){
        this.$message.error("请输入正确手机号");
      }
      //发起请求
      getCode(this.loginForm.phone).then(res=>{
        if(res.data.code!=200){
          this.$message.error("获取验证码失败,请检查手机号码是否正确")
        }
      })

    },
    //登录
    login(){
      //发起请求
      login(this.loginForm).then(res=>{
        if(res.data.code==200){
          localStorage.setItem("token",res.data.data);
          this.$message.success("登录成功")
          //跳转首页
          this.$router.push('/ProductList');
        }
      })
    },
    keyDown(e){
      //如果是回车则执行登录方法
      if(e.keyCode == 13){
        //需要执行的方法
        this.login();
      }
    },
    // 判断自定义输入事件
    handerInput() {
      // 判断不能输入小数点
      let str = '' + this.loginForm.phone;
      if (str.indexOf('.') !== -1) {
        let arr = str.split('');
        arr.splice(arr.length - 1);
        let str2 = arr.join('');
        this.loginForm.phone = +str2;
      }
    },
  },
    created() {
      layui.config({
        base: '../../../../static/static/js/'
      }).use('house');
    },
  mounted () {
    //绑定事件
    window.addEventListener('keydown',this.keyDown);
  },
  //销毁事件
  destroyed(){
    window.removeEventListener('keydown',this.keyDown,false);
  },
  }
</script>
<!--去掉type=number自带的上下箭头-->
<style scoped>

  input[type=number] {
    -moz-appearance:textfield;
  }
  input[type=number]::-webkit-inner-spin-button,
  input[type=number]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
  }
</style>


login.js

import request from '../../utils/request';
//获取验证码
export const getCode = phone => {
    return request({
        url: 'http://localhost:5052/member/'+phone,
        method: 'get',
    });
};
//登录
export const login = query => {
    return request({
        url: 'http://localhost:5052/member/login',
        method: 'post',
        params: query
    });
};

request.js

import axios from 'axios';
import router from '../router'

const service = axios.create({
    timeout: 500000000000
});

service.interceptors.request.use(config=>{
    // alert(localStorage.getItem("token"));
    config.headers.common["Authorization-token"]=localStorage.getItem("token");
    return config;
})

service.interceptors.response.use(response=>{
    var code=response.data.code;
    if( code != 200 && code==1004){
        router.push("/login");
        return Promise.reject('error');
    }
    return response;
})
export default service;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jq1223

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值