注:此项目为微服务项目,前后端分离 vue+springboot+springcloud+layui

前端登录页面:

实现短信验证码登录_spring


所使用的的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);
}
}

实现短信验证码登录_json_02

在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;