项目8:用户注册和登录的前后端联调
项目8:用户注册和登录的前后端联调
1.前端项目使用
2.前端项目注册模块
3.后端完成项目注册
4.前端项目登录模块
5.后端完成项目登录
6.用户认证(校验用户是否登录)
项目8:用户注册和登录的前后端联调
1.前端项目使用
- 直接使用提供的srb-site前端页面
2.前端项目注册模块
①前端项目注册模块逻辑
- 注册(投资人1 借款人2)
- 利用手机号发送验证码注册
- 输入密码点击下一步
- 注册成功
②前端页面
pages\\register.vue
- 封装的数据
userinfo(userType,mobile,code,password) - 前端页面
<template><!--注册--><div class="wrap"><div v-if="step === 1" class="tdbModule register"><div class="registerTitle">注册账户</div><div class="registerLc1"><p class="p1">填写账户信息</p><p class="p2">注册成功</p></div><div class="registerCont"><ul><li><span class="dis"></span><input v-model="userInfo.userType" type="radio" value="1" />我要投资<input v-model="userInfo.userType" type="radio" value="2" />我要借钱</li><li class="telNumber"><span class="dis">手机号码</span><input class="input" v-model="userInfo.mobile" /><!--没发验证码显式上面的v-if,发了显示下面的v-else--><button v-if="!sending" class="button" @click="send()">获取验证码</button><button v-else disabled class="button disabled">{{ leftSecond }}秒后重发</button></li><li><span class="dis">短信验证码</span><input class="input" v-model="userInfo.code" /><span class="info">请输入验证码</span></li><li><span class="dis">密码</span><input type="password" v-model="userInfo.password" class="input" /><span class="info">6-24个字符,英文、数字组成,区分大小写</span></li><li class="agree"><input type="checkbox" checked />我同意《<NuxtLink to="#" target="_black">尚融宝注册协议</NuxtLink>》<span>请查看协议</span></li><li class="btn"><button @click="register()">下一步</button></li></ul></div></div><div v-if="step === 2" class="tdbModule register"><div class="registerTitle">注册账户</div><div class="registerLc2"><p class="p1">填写账户信息</p><p class="p2">注册成功</p></div><div class="registerCont"><ul><li class="scses">{{ this.userInfo.mobile }} 恭喜您注册成功!<NuxtLink class="blue" to="/login">请登录</NuxtLink></li></ul></div></div></div>
</template><script>
import '~/assets/css/register.css'
export default {data() {return {step: 1, //注册步骤userInfo: {userType: 1,},sending: false, // 是否发送验证码second: 10, // 倒计时间leftSecond: 0, //剩余时间}},methods: {//发短信send() {//防止空手机号输入if (!this.userInfo.mobile) {this.$message.error('请输入手机号')return}//防止重复提交if (this.sending) returnthis.sending = true//倒计时this.timeDown()//调用后端接口this.$axios.$get('/api/sms/send/' + this.userInfo.mobile).then((response) => {//前端响应框this.$message.success(response.message)})},//倒计时timeDown() {console.log('进入倒计时')this.leftSecond = this.second//计时器,每隔一秒,执行一次函数const timmer = setInterval(() => {this.leftSecond--if (this.leftSecond <= 0) {clearInterval(timmer)this.sending = false}}, 1000)},//注册register() {this.$axios.$post('/api/core/userInfo/register', this.userInfo).then((response) => {//注册成功表单this.step = 2})},},
}
</script>
3.后端完成项目注册
流程
测试过程中关闭sms的具体使用aliyun发送短信的业务,直接存入redis即可,省钱。。
后端接收到前端封装的数据,需要校验短信验证码,需要保存数据到数据库
①数据库设计(前端注册后需要插入的表)
user_info
user_account
user_account的user_id和user_info的user_id绑定
②创建vo对象(方便封装前端穿过的表单)
package com.atguigu.srb.core.pojo.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description="注册对象")
public class RegisterVO {@ApiModelProperty(value = "用户类型")private Integer userType;@ApiModelProperty(value = "手机号")private String mobile;@ApiModelProperty(value = "验证码")private String code;@ApiModelProperty(value = "密码")private String password;
}
③编写注册controller(api让前端调用)
package com.atguigu.srb.core.controller.api;import com.atguigu.common.exception.Assert;
import com.atguigu.common.result.R;
import com.atguigu.common.result.ResponseEnum;
import com.atguigu.common.util.RegexValidateUtils;
import com.atguigu.srb.core.pojo.vo.RegisterVO;
import com.atguigu.srb.core.service.UserInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;/* <p>* 用户基本信息 前端控制器* </p> @author Likejin* @since 2023-04-09*/
@Api(tags = "会员接口")
@RestController
@RequestMapping("/api/core/userInfo")
@Slf4j
@CrossOrigin
public class UserInfoController {@Resourceprivate RedisTemplate redisTemplate;@Resourceprivate UserInfoService userInfoService;@ApiOperation("会员注册")@PostMapping("/register")public R register(@RequestBody RegisterVO registerVO){String mobile = registerVO.getMobile();String password = registerVO.getPassword();String code = registerVO.getCode();//校验验证码是否正确String codeGen = (String)redisTemplate.opsForValue().get("srb:sms:code:" + mobile);//防止无脑攻击Assert.notEmpty(mobile,ResponseEnum.MOBILE_NULL_ERROR);Assert.notEmpty(password,ResponseEnum.PASSWORD_NULL_ERROR);Assert.notEmpty(code,ResponseEnum.CODE_NULL_ERROR);Assert.isTrue(RegexValidateUtils.checkCellphone(mobile),ResponseEnum.MOBILE_ERROR);//没匹配成功报错Assert.equals(code,codeGen, ResponseEnum.CODE_ERROR);//注册userInfoService.register(registerVO);return R.ok().message("注册成功");}}
④业务层service调用
package com.atguigu.srb.core.service;import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.pojo.vo.RegisterVO;
import com.baomidou.mybatisplus.extension.service.IService;/* <p>* 用户基本信息 服务类* </p> @author Likejin* @since 2023-04-09*/
public interface UserInfoService extends IService<UserInfo> {void register(RegisterVO registerVO);
}
package com.atguigu.srb.core.service.impl;import com.atguigu.common.exception.Assert;
import com.atguigu.common.result.ResponseEnum;
import com.atguigu.common.util.MD5;
import com.atguigu.srb.core.mapper.UserAccountMapper;
import com.atguigu.srb.core.mapper.UserInfoMapper;
import com.atguigu.srb.core.pojo.entity.UserAccount;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.pojo.vo.RegisterVO;
import com.atguigu.srb.core.service.UserInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;/* <p>* 用户基本信息 服务实现类* </p> @author Likejin* @since 2023-04-09*/
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {@Resourceprivate UserAccountMapper userAccountMapper;@Transactional(rollbackFor = Exception.class)@Overridepublic void register(RegisterVO registerVO) {//判断当前用户是否已经被注册QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();userInfoQueryWrapper.eq("mobile",registerVO.getMobile());//baseMapper被封装为UserInfoMapperInteger count = baseMapper.selectCount(userInfoQueryWrapper);Assert.isTrue(count==0, ResponseEnum.MOBILE_EXIST_ERROR);//插入用户信息记录 user_infoUserInfo userInfo = new UserInfo();userInfo.setUserType(registerVO.getUserType());userInfo.setNickName(registerVO.getMobile());userInfo.setName(registerVO.getMobile());userInfo.setMobile(registerVO.getMobile());userInfo.setPassword(MD5.encrypt(registerVO.getPassword()));userInfo.setStatus(UserInfo.STATUS_NORMAL); //正常userInfo.setHeadImg(UserInfo.USER_AVATAR);baseMapper.insert(userInfo);//插入用户账户记录 user_accountUserAccount userAccount = new UserAccount();userAccount.setUserId(userInfo.getId());userAccountMapper.insert(userAccount);}
}
⑥细节
- 修改UserInfo增加常量啊
//上锁状态正常为1,不正常为0public static final Integer STATUS_NORMAL = 1;public static final Integer STATUS_LOCKED = 0;//头像地址public static final String USER_AVATAR ="https://srb-file-200921-lkj.oss-cn-beijing.aliyuncs.com/test/2023/04/12/4a50f632-8111-4c18-9232-2e58eee69bfe.png";
- 修改号码验证让自己的手机号好使
String regex = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0-9]))\\\\d{8}$";
- 引入加密工具加密密码
package com.atguigu.common.util;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public final class MD5 {public static String encrypt(String strSrc) {try {char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'a', 'b', 'c', 'd', 'e', 'f' };byte[] bytes = strSrc.getBytes();MessageDigest md = MessageDigest.getInstance("MD5");md.update(bytes);bytes = md.digest();int j = bytes.length;char[] chars = new char[j * 2];int k = 0;for (int i = 0; i < bytes.length; i++) {byte b = bytes[i];chars[k++] = hexChars[b >>> 4 & 0xf];chars[k++] = hexChars[b & 0xf];}return new String(chars);} catch (NoSuchAlgorithmException e) {e.printStackTrace();throw new RuntimeException("MD5加密出错!!+" + e);}}}
4.前端项目登录模块
①实现流程
- 用户选择投资人,借款人
- 输入手机号密码 立即登录
②前端页面
- 封装的数据
userInfo(userType,mobile,password) - 前端页面
pages\\login.vue
将token保存到cookie中
<template><!--登录--><div class="wrap"><div class="tdbModule loginPage"><div class="registerTitle">用户登录</div><div class="registerCont"><ul><li><span class="dis"></span><input v-model="userInfo.userType" type="radio" value="1" />投资人<input v-model="userInfo.userType" type="radio" value="2" />借款人</li><li><span class="dis">手机号:</span><input class="input" v-model="userInfo.mobile" /></li><li><span class="dis">密码:</span><input class="input" v-model="userInfo.password" type="password" /></li><li class="btn"><button @click="login()" :class="{ disabled: !isValid }">立即登录</button></li></ul></div></div></div>
</template><script>
import '~/assets/css/register.css'
//引入cookie模块
import cookie from 'js-cookie'export default {data() {return {userInfo: {userType: 1,},isValid: true, //表单校验是否成功}},methods: {//登录login() {this.$axios.$post('/api/core/userInfo/login', this.userInfo).then((response) => {console.log(response.data)//利用cookie存token(后面只需要验证token即可)cookie.set('userInfo', response.data.userInfo)window.location.href = '/user'})},},
}
</script>
5.后端完成项目登录
①引入jwt包和jwt工具
<!--访问令牌--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId></dependency></dependencies>
package com.atguigu.srb.base.util;import com.atguigu.common.exception.BusinessException;
import com.atguigu.common.result.ResponseEnum;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;public class JwtUtils {private static long tokenExpiration = 24*60*60*1000;private static String tokenSignKey = "A1t2g3uigu123456";/* @param :* @return Key* @author Likejin* @description 生成了一个Key类型的秘钥* @date 2023/4/13 15:38*/private static Key getKeyInstance(){SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;byte[] bytes = DatatypeConverter.parseBase64Binary(tokenSignKey);return new SecretKeySpec(bytes,signatureAlgorithm.getJcaName());}/* @param userId:* @param userName:* @return String* @author Likejin* @description 创建token* @date 2023/4/13 15:37*/public static String createToken(Long userId, String userName) {String token = Jwts.builder().setSubject("SRB-USER").setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)).claim("userId", userId).claim("userName", userName).signWith(SignatureAlgorithm.HS512, getKeyInstance()).compressWith(CompressionCodecs.GZIP).compact();return token;}/* 判断token是否有效* @param token* @return*/public static boolean checkToken(String token) {if(StringUtils.isEmpty(token)) {return false;}try {Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);return true;} catch (Exception e) {return false;}}public static Long getUserId(String token) {Claims claims = getClaims(token);Integer userId = (Integer)claims.get("userId");return userId.longValue();}public static String getUserName(String token) {Claims claims = getClaims(token);return (String)claims.get("userName");}public static void removeToken(String token) {//jwttoken无需删除,客户端扔掉即可。}/* 校验token并返回Claims* @param token* @return*/private static Claims getClaims(String token) {if(StringUtils.isEmpty(token)) {// LOGIN_AUTH_ERROR(-211, "未登录"),throw new BusinessException(ResponseEnum.LOGIN_AUTH_ERROR);}try {Jws<Claims> claimsJws = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);Claims claims = claimsJws.getBody();return claims;} catch (Exception e) {throw new BusinessException(ResponseEnum.LOGIN_AUTH_ERROR);}}
}
②写前端传来的vo对象
package com.atguigu.srb.core.pojo.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/* @author Likejin* @description 封装登录对象* @date 2023/4/13 15:42*/@Data
@ApiModel(description="登录对象")
public class LoginVO {@ApiModelProperty(value = "用户类型")private Integer userType;@ApiModelProperty(value = "手机号")private String mobile;@ApiModelProperty(value = "密码")private String password;
}
③前端展示用户信息封装vo
package com.atguigu.srb.core.pojo.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/* @author Likejin* @description 展示用户信息类* @date 2023/4/13 15:42*/@Data
@ApiModel(description="用户信息对象")
public class UserInfoVO {@ApiModelProperty(value = "用户姓名")private String name;@ApiModelProperty(value = "用户昵称")private String nickName;@ApiModelProperty(value = "头像")private String headImg;@ApiModelProperty(value = "手机号")private String mobile;@ApiModelProperty(value = "1:出借人 2:借款人")private Integer userType;@ApiModelProperty(value = "JWT访问令牌")private String token;
}
④controller层的编写
package com.atguigu.srb.core.controller.api;import com.atguigu.common.exception.Assert;
import com.atguigu.common.result.R;
import com.atguigu.common.result.ResponseEnum;
import com.atguigu.common.util.RegexValidateUtils;
import com.atguigu.srb.core.pojo.vo.LoginVO;
import com.atguigu.srb.core.pojo.vo.RegisterVO;
import com.atguigu.srb.core.pojo.vo.UserInfoVO;
import com.atguigu.srb.core.service.UserInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;/* <p>* 用户基本信息 前端控制器* </p> @author Likejin* @since 2023-04-09*/
@Api(tags = "会员接口")
@RestController
@RequestMapping("/api/core/userInfo")
@Slf4j
@CrossOrigin
public class UserInfoController {@Resourceprivate RedisTemplate redisTemplate;@Resourceprivate UserInfoService userInfoService;@ApiOperation("会员注册")@PostMapping("/register")public R register(@RequestBody RegisterVO registerVO){String mobile = registerVO.getMobile();String password = registerVO.getPassword();String code = registerVO.getCode();//校验验证码是否正确String codeGen = (String)redisTemplate.opsForValue().get("srb:sms:code:" + mobile);//防止无脑攻击Assert.notEmpty(mobile,ResponseEnum.MOBILE_NULL_ERROR);Assert.notEmpty(password,ResponseEnum.PASSWORD_NULL_ERROR);Assert.notEmpty(code,ResponseEnum.CODE_NULL_ERROR);Assert.isTrue(RegexValidateUtils.checkCellphone(mobile),ResponseEnum.MOBILE_ERROR);//没匹配成功报错Assert.equals(code,codeGen, ResponseEnum.CODE_ERROR);//注册userInfoService.register(registerVO);return R.ok().message("注册成功");}@ApiOperation("会员登录")@PostMapping("/login")public R login(@RequestBody LoginVO loginVO, HttpServletRequest request){String mobile = loginVO.getMobile();String password = loginVO.getPassword();Assert.notEmpty(mobile,ResponseEnum.MOBILE_NULL_ERROR);Assert.notEmpty(password,ResponseEnum.PASSWORD_NULL_ERROR);//记录用户登录日志(user_login_record)String ip = request.getRemoteAddr();UserInfoVO userInfoVO = userInfoService.login(loginVO,ip);return R.ok().data("userInfo",userInfoVO);}}
⑤service层的编写
package com.atguigu.srb.core.service;import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.pojo.vo.LoginVO;
import com.atguigu.srb.core.pojo.vo.RegisterVO;
import com.atguigu.srb.core.pojo.vo.UserInfoVO;
import com.baomidou.mybatisplus.extension.service.IService;/* <p>* 用户基本信息 服务类* </p> @author Likejin* @since 2023-04-09*/
public interface UserInfoService extends IService<UserInfo> {void register(RegisterVO registerVO);UserInfoVO login(LoginVO loginVO, String ip);
}
package com.atguigu.srb.core.service.impl;import com.atguigu.common.exception.Assert;
import com.atguigu.common.result.ResponseEnum;
import com.atguigu.common.util.MD5;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.core.mapper.UserAccountMapper;
import com.atguigu.srb.core.mapper.UserInfoMapper;
import com.atguigu.srb.core.mapper.UserLoginRecordMapper;
import com.atguigu.srb.core.pojo.entity.UserAccount;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.pojo.entity.UserLoginRecord;
import com.atguigu.srb.core.pojo.vo.LoginVO;
import com.atguigu.srb.core.pojo.vo.RegisterVO;
import com.atguigu.srb.core.pojo.vo.UserInfoVO;
import com.atguigu.srb.core.service.UserInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;/* <p>* 用户基本信息 服务实现类* </p> @author Likejin* @since 2023-04-09*/
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {@Resourceprivate UserAccountMapper userAccountMapper;@Resourceprivate UserLoginRecordMapper userLoginRecordMapper;@Transactional(rollbackFor = Exception.class)@Overridepublic void register(RegisterVO registerVO) {//判断当前用户是否已经被注册QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();userInfoQueryWrapper.eq("mobile",registerVO.getMobile());//baseMapper被封装为UserInfoMapperInteger count = baseMapper.selectCount(userInfoQueryWrapper);Assert.isTrue(count==0, ResponseEnum.MOBILE_EXIST_ERROR);//插入用户信息记录 user_infoUserInfo userInfo = new UserInfo();userInfo.setUserType(registerVO.getUserType());userInfo.setNickName(registerVO.getMobile());userInfo.setName(registerVO.getMobile());userInfo.setMobile(registerVO.getMobile());userInfo.setPassword(MD5.encrypt(registerVO.getPassword()));userInfo.setStatus(UserInfo.STATUS_NORMAL); //正常userInfo.setHeadImg(UserInfo.USER_AVATAR);baseMapper.insert(userInfo);//插入用户账户记录 user_accountUserAccount userAccount = new UserAccount();userAccount.setUserId(userInfo.getId());userAccountMapper.insert(userAccount);}/* @param loginVO: * @param ip: * @return UserInfoVO* @author Likejin* @description 用户登录功能* @date 2023/4/13 16:17*/@Transactional(rollbackFor = Exception.class)@Overridepublic UserInfoVO login(LoginVO loginVO, String ip) {String mobile = loginVO.getMobile();String password = loginVO.getPassword();Integer userType = loginVO.getUserType();//用户名是否存在QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();userInfoQueryWrapper.eq("mobile",mobile).eq("User_type",userType);UserInfo userInfo = baseMapper.selectOne(userInfoQueryWrapper);Assert.notNull(userInfo,ResponseEnum.LOGIN_MOBILE_ERROR);//密码是否正确Assert.equals(MD5.encrypt(password),userInfo.getPassword(),ResponseEnum.LOGIN_PASSWORD_ERROR);//用户是否被禁用Assert.equals(userInfo.getStatus(),UserInfo.STATUS_NORMAL,ResponseEnum.LOGIN_LOKED_ERROR);//记录登录日志UserLoginRecord userLoginRecord = new UserLoginRecord();userLoginRecord.setUserId(userInfo.getId());userLoginRecord.setIp(ip);userLoginRecordMapper.insert(userLoginRecord);//生成tokenString token = JwtUtils.createToken(userInfo.getId(), userInfo.getPassword());//组装UserInfoVoUserInfoVO userInfoVO = new UserInfoVO();userInfoVO.setToken(token);userInfoVO.setName(userInfo.getName());userInfoVO.setNickName(userInfo.getNickName());userInfoVO.setHeadImg(userInfo.getHeadImg());userInfoVO.setMobile(userInfo.getMobile());userInfoVO.setUserType(userInfo.getUserType());return userInfoVO;}
}
结果
前端保存了后端传来的token
6.用户认证(校验用户是否登录)
①如何校验
- 登录后后端返回userinfo数据(包含token数据,保存在cookie中)
- 前端在其APPHeader中展示
如果登录展示用户数据
如果为登录展示注册或登录 - 每次在APPHeader渲染完成之后
发送ajax请求,有token则校验token然后展示用户信息 - 因为每次许多服务都需要去验证token是否登录,将token信息写入请求头中统一写在请求拦截器中
- 实现功能
只要发送ajax请求,就判断cookie中是否有token,如果有token就将其放在请求头中,需要校验token的就调用校验接口校验成功后实现逻辑
②前端代码
components\\AppHeader.vue
<template><header><div class="header-top min-width"><div class="container fn-clear"><strong class="fn-left">咨询热线:400-000-0000<span class="s-time">服务时间:9:00 - 18:00</span></strong><ul class="header_contact"><li class="c_1"><a class="ico_head_weixin" id="wx"></a></li><li class="c_2"><a href="#" target="_blank" title="官方QQ" alt="官方QQ"><b class="ico_head_QQ"></b></a></li><li class="c_4"><a href="#" target="_blank" title="新浪微博" alt="新浪微博"><b class="ico_head_sina"></b></a></li></ul><!-- 用户未登录 --><ul v-if="!userInfo" class="fn-right header-top-ul"><!-- <li><a href="" :class="'c-orange'">测试</a></li> --><li><NuxtLink to="/" :class="{ 'c-orange': $route.fullPath === '/' }">返回首页</NuxtLink></li><li><div class=""><NuxtLinkto="/register":class="{ 'c-orange': $route.fullPath === '/register' }">免费注册</NuxtLink></div></li><li><div class=""><NuxtLinkto="/login":class="{ 'c-orange': $route.fullPath === '/login' }">登录</NuxtLink></div></li></ul><!-- 用户已登录 --><ul v-if="userInfo" class="fn-right header-top-ul"><li><NuxtLink to="/" class="app">返回首页</NuxtLink></li><li><div class=""><NuxtLink to="/user" class="user" title="我的账户"><i class="el-icon-user-solid">{{ userInfo.nickName }}</i></NuxtLink></div></li><li><div class=""><ahref="javascript:void(0)"class="js-login"@click="logout()"title="退出">退出</a></div></li></ul></div></div><div class="header min-width"><div class="container"><div class="fn-left logo"><NuxtLink to="/"><img src="~/assets/images/logo.png" title="" /></NuxtLink></div><ul class="top-nav fn-clear"><li :class="{ on: $route.fullPath === '/' }"><NuxtLink to="/">首页</NuxtLink></li><li :class="{ on: $route.fullPath === '/list' }"><NuxtLink to="/lend"> 我要投资 </NuxtLink></li><li :class="{ on: $route.fullPath === '/help' }"><NuxtLink to="/help">安全保障</NuxtLink></li><li :class="{ on: $route.fullPath === '/about' }"><NuxtLink to="/about">关于我们</NuxtLink></li></ul></div></div></header>
</template>
<script>
import '~/assets/font/iconfont.css'
import cookie from 'js-cookie'export default {data() {return {userInfo: null,}},mounted() {//如果写created的话,需要在浏览器渲染之后,在能获得cookiethis.showInfo()},methods: {//显示用户信息//1.从cookie中获取用户信息,如果不存在用户信息则用户未登录//2.存在用户信息则需要校验token是否为合法tokenshowInfo() {//判断coolie中有没有值let userinfo = cookie.get('userInfo')if (!userinfo) {console.log('coolie不存在')this.userInfo = nullreturn}userinfo = JSON.parse(userinfo)//校验token是否合法this.$axios({url: '/api/core/userInfo/checkToken',method: 'get',//因为每次访问许多服务都需要校验,直接写在请求拦截器中headers: {token: userinfo.token,},}).then((response) => {console.log('校验成功')this.userInfo = userinfo})},//退出,需要销毁cookielogout() {cookie.set('userInfo', '')window.location.href = '/login'},},
}
</script>
plugins\\axios.js请求拦截器
$axios.onRequest((config) => {let userInfo = cookie.get('userInfo')if (userInfo) {// debuggeruserInfo = JSON.parse(userInfo)config.headers['token'] = userInfo.token}console.log('Making request to ' + config.url)})
③后端校验token
package com.atguigu.srb.core.controller.api;import com.atguigu.common.exception.Assert;
import com.atguigu.common.result.R;
import com.atguigu.common.result.ResponseEnum;
import com.atguigu.common.util.RegexValidateUtils;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.core.pojo.vo.LoginVO;
import com.atguigu.srb.core.pojo.vo.RegisterVO;
import com.atguigu.srb.core.pojo.vo.UserInfoVO;
import com.atguigu.srb.core.service.UserInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;/* <p>* 用户基本信息 前端控制器* </p> @author Likejin* @since 2023-04-09*/
@Api(tags = "会员接口")
@RestController
@RequestMapping("/api/core/userInfo")
@Slf4j
@CrossOrigin
public class UserInfoController {@Resourceprivate RedisTemplate redisTemplate;@Resourceprivate UserInfoService userInfoService;@ApiOperation("会员注册")@PostMapping("/register")public R register(@RequestBody RegisterVO registerVO){String mobile = registerVO.getMobile();String password = registerVO.getPassword();String code = registerVO.getCode();//校验验证码是否正确String codeGen = (String)redisTemplate.opsForValue().get("srb:sms:code:" + mobile);//防止无脑攻击Assert.notEmpty(mobile,ResponseEnum.MOBILE_NULL_ERROR);Assert.notEmpty(password,ResponseEnum.PASSWORD_NULL_ERROR);Assert.notEmpty(code,ResponseEnum.CODE_NULL_ERROR);Assert.isTrue(RegexValidateUtils.checkCellphone(mobile),ResponseEnum.MOBILE_ERROR);//没匹配成功报错Assert.equals(code,codeGen, ResponseEnum.CODE_ERROR);//注册userInfoService.register(registerVO);return R.ok().message("注册成功");}@ApiOperation("会员登录")@PostMapping("/login")public R login(@RequestBody LoginVO loginVO, HttpServletRequest request){String mobile = loginVO.getMobile();String password = loginVO.getPassword();Assert.notEmpty(mobile,ResponseEnum.MOBILE_NULL_ERROR);Assert.notEmpty(password,ResponseEnum.PASSWORD_NULL_ERROR);//记录用户登录日志(user_login_record)String ip = request.getRemoteAddr();UserInfoVO userInfoVO = userInfoService.login(loginVO,ip);return R.ok().data("userInfo",userInfoVO);}/* @param request:* @return R* @author Likejin* @description 后端得到cookie中存储的token* @date 2023/4/13 16:28*/@ApiOperation("校验令牌")@GetMapping("/checkToken")public R checkToken(HttpServletRequest request) {//获取请求头中的tokenString token = request.getHeader("token");boolean result = JwtUtils.checkToken(token);if(result){return R.ok();}else{//LOGIN_AUTH_ERROR(-211, "未登录"),return R.setResult(ResponseEnum.LOGIN_AUTH_ERROR);}}}
④实现结果