注:此项目为微服务项目,前后端分离 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>家居商城版权所有 © 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;