1. 用户登录业务介绍
1.1 单一服务器模式登录
- 使用session对象实现
登录成功后,把用户数据放到session里面,判断是否登录,从session里面获取数据,可以获取到登录
1.2 单点登录
web系统由单系统发展成多系统组成的应用群,复杂性应该由系统内部承担,而不是用户。无论web系统内部多么复杂,对用户而言,都是一个统一的整体,也就是说,用户访问web系统的整个应用群与访问单个系统一样,登录/注销只要一次就够了
1.3 单点登录的常用三种方式
1.3.1. session广播机制实现
利用了session复制(如果模块过多,session复制会浪费大量的资料,占用大量的空间)session;默认过期时间30分钟
1.3.2 使用cookie+redis实现
- 在项目中任何一个模板进行登录,登录之后,把数据放在两个地方
- redis:在key生成一个唯一值(ip、用户id等),在value使用用户的数据
- cookie:把redis里面生成的cookie值放到redis里面
- 访问项目中的其他模块,发送请求带着cookie进行发送,获取cookie值,拿着cookie做事情:把cookie获取的值,到redis进行查询根据key进行查询,如果查询到数据就是登录
1.3.3 使用token实现
- 在项目某个模块进行登录,登录之后,按照规则生成字符串,把登录之后的用户信息包含到字符串里面,把字符串返回(可以把字符串通过cookie返回,也可以把字符串通过地址栏返回)
- 在去访问项目其他模块,每次访问在地址栏带着生成的字符串,在访问模块里面‘获取地址栏的字符串,根据字符串获取用户信息,如果可以获取到就是登录
2.使用JWT进行跨域身份验证
2.1传统用户身份验证
Internet服务无法与用户身份验证分开。一般过程如下:
- 用户向服务器发送用户名和密码。
- 验证服务器后,相关数据(如用户角色,登录时间等)将保存在当前会话中。
- 服务器向用户返回session_id,session信息都会写入到用户的Cookie。
- 用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。
- 服务器收到session_id并对比之前保存的数据,确认用户的身份。
这种模式最大的问题是,没有分布式架构,无法支持横向扩展。
2.2解决方案
- session广播
- 将透明令牌存入cookie,将用户身份信息存入redis
- 另外一种灵活的解决方案:
使用自包含令牌,通过客户端保存数据,而服务器不保存会话数据。 JWT是这种解决方案的代表。
2.3JWT
2.3.1概述
JWT就是给你们规定好的规则,使用JWT规则可以生成字符串,包含用户信息
2.3.2 JWT的组成
该对象为一个很长的字符串,字符之间通过"."分隔符分为三个子串。
每一个子串表示了一个功能块,总共有以下三个部分:JWT头信息、有效载荷(主体部分、用户信息)和签名(防伪标志)
2.3.3 项目添加JWT工具类
2.3.3.1在common_utils模块中添加jwt工具依赖
<!-- JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
2.3.3.2创建JWT工具类
在common_utils的模块下创建一个JwtUtils类
public class JwtUtils {
public static final long EXPIRE = 1000 * 60 * 60 * 24;//Token过期时间
public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO"; //密钥
//生成Token字符串
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
//设置JWT头部分
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
.setSubject("guli-user")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))//设置过期时间
//设置token的主体部分
.claim("id", id)
.claim("nickname", nickname)
//密钥
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
.compact();
return JwtToken;
}
/**
* 判断token是否存在与有效
* @param jwtToken
* @return
*/
public static boolean checkToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
* @param request
* @return
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token获取会员id
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("id");
}
}
3. 整合阿里云的短信
3.1新建短信微服务
- 在service模块下创建子模块service-msm
- application.properties配置
3.2 在阿里云中开通短信服务
- 开通阿里云的短信服务
- 进入控制台,点击国内消息,需要申请两个内容
- 模板管理的申请
点击模板管理,选择添加模板
进行选择
- 添加前面管理
选择签名管理,点击添加签名
由于现在我有些东西没有
3.3 编写代码实现短信发送
3.3.1引入相关的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
</dependency>
3.3.2 application.perperties
# 服务端口
server.port=8005
# 服务名
spring.application.name=service-msm
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=199866
spring.redis.host=47.93.21.100
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
#最小空闲
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3.3.3创建一个生成随机数的实体类
public class RandomUtil {
private static final Random random = new Random();
private static final DecimalFormat fourdf = new DecimalFormat("0000");
private static final DecimalFormat sixdf = new DecimalFormat("000000");
public static String getFourBitRandom() {
return fourdf.format(random.nextInt(10000));
}
public static String getSixBitRandom() {
return sixdf.format(random.nextInt(1000000));
}
/**
* 给定数组,抽取n个数据
* @param list
* @param n
* @return
*/
public static ArrayList getRandom(List list, int n) {
Random random = new Random();
HashMap<Object, Object> hashMap = new HashMap<Object, Object>();
// 生成随机数字并存入HashMap
for (int i = 0; i < list.size(); i++) {
int number = random.nextInt(100) + 1;
hashMap.put(number, i);
}
// 从HashMap导入数组
Object[] robjs = hashMap.values().toArray();
ArrayList r = new ArrayList();
// 遍历数组并打印数据
for (int i = 0; i < n; i++) {
r.add(list.get((int) robjs[i]));
System.out.print(list.get((int) robjs[i]) + "\t");
}
System.out.print("\n");
return r;
}
}
创建一个MDK5加密的工具类
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);
}
}
public static void main(String[] args) {
System.out.println(MD5.encrypt("111111"));
}
}
3.3.4 Controller接口
@RestController
@RequestMapping("/edumsm/msm")
@CrossOrigin
@Api(tags = "短信服务")
public class MsmController {
@Autowired
private MsmService msmService;
@Autowired
private RedisTemplate<String,String> redisTemplate;
//发送短信的方法
@GetMapping("/send/{phone}")
@ApiOperation("发送短信")
public R sendMsm(@PathVariable String phone)
{
//从redis获取验证码,如果可以获取到直接返回
String code = redisTemplate.opsForValue().get(phone);
if(!StringUtils.isEmpty(code))
{
return R.ok();
}
//生成随机值,传递阿里云进行发送
String random = RandomUtil.getFourBitRandom();
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("code",random);
//调用service发送短信
boolean isSend= msmService.send(hashMap,phone);
if(isSend)
{
//发送成功,把验证码放到redis,并设置有效时间
redisTemplate.opsForValue().set(phone,random,5, TimeUnit.MINUTES);
return R.ok();
}
else
{
return R.error().message("短信发送失败");
}
}
}
3.3.5service
@Service
public class MsmServiceImpl implements MsmService {
//发送短信
@Override
public boolean send(HashMap<String, Object> hashMap, String phone) {
//由于短信服务开通不成功,所有返回true
return true;
}
}
4.登录接口
4.1创建登录的模块
4.1.1创建service-Ucenter模块
在service模块下创建子模块service-ucenter
4.1.2.创建数据库,用代码生成器生成代码
数据库
CREATE TABLE `ucenter_member` (
`id` char(19) NOT NULL COMMENT '会员id',
`openid` varchar(128) DEFAULT NULL COMMENT '微信openid',
`mobile` varchar(11) DEFAULT '' COMMENT '手机号',
`password` varchar(255) DEFAULT NULL COMMENT '密码',
`nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
`sex` tinyint(2) unsigned DEFAULT NULL COMMENT '性别 1 女,2 男',
`age` tinyint(3) unsigned DEFAULT NULL COMMENT '年龄',
`avatar` varchar(255) DEFAULT NULL COMMENT '用户头像',
`sign` varchar(100) DEFAULT NULL COMMENT '用户签名',
`is_disabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否禁用 1(true)已禁用, 0(false)未禁用',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员表';
代码生成器
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir("D:\\尚硅谷在线教育项目\\在线教育--谷粒学院\\项目源码\\day10\\后端代码\\后端代码\\guli_parent\\service\\service-ucenter" + "/src/main/java");
gc.setAuthor("smile");
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
//UserServie
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.ID_WORKER_STR); //主键策略
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("199866");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
// pc.setModuleName("educenter"); //模块名
//包 com.atguigu.eduservice
pc.setParent("com.blb");
//包 com.atguigu.eduservice.controller
pc.setController("controller");
pc.setEntity("domain");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("ucenter_member");
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
4.1.3 Controller
@RestController
@RequestMapping("/eudcenter/member")
@CrossOrigin
public class UcenterMemberController {
@Autowired
private UcenterMemberService memberService;
//登录
@PostMapping("/logign")
public R loginUser(@RequestBody UcenterMember ucenterMember)
{
//调用service实现登录返回token值
String token= memberService.login(ucenterMember);
return R.ok().data("token",token);
}
}
4.1.4service
@Service
public class UcenterMemberServiceImpl extends ServiceImpl<UcenterMemberMapper, UcenterMember> implements UcenterMemberService {
@Override
public String login(UcenterMember member) {
//获取手机号和密码
String mobile = member.getMobile();
String password = member.getPassword();
//手机号和密码有一个为空时
if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password))
{
throw new GuliException(20001,"登录失败");
}
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile",mobile);
UcenterMember member1 = baseMapper.selectOne(wrapper);
//判断该手机号的用户是否存在
if(member1==null)
{
throw new GuliException(20001,"该用户不存在");
}
//判断密码
//因为存储到数据库的密码肯定是加密的 将输入的密码进行加密然后在与数据库的密码进行比较
//加密方式 MD5加密
if(!MD5.encrypt(password).equals(member1.getPassword()))
{
throw new GuliException(20001,"密码错误");
}
//判断用户是否禁用
if(member1.getIsDisabled())
{
throw new GuliException(20001,"登录失败");
}
//登录成功 生成token
String jwtToken = JwtUtils.getJwtToken(member1.getId(), member1.getNickname());
return jwtToken;
}
}
5.用户注册
5.1 创建实体类,封装注册数据,包含验证码属性
@ApiModel("用户注册")
@Data
public class RegisterVo {
@ApiModelProperty(value = "昵称")
private String nicknanme;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "验证码")
private String code;
}
5.2用户注册的接口
//注册
@PostMapping("/register")
@ApiOperation("用户注册")
public R register(@RequestBody RegisterVo registerVo)
{
memberService.register(registerVo);
return R.ok();
}
5.3用户注册service
//用户注册
@Override
public void register(RegisterVo registerVo) {
if(StringUtils.isEmpty(registerVo.getCode())||StringUtils.isEmpty(registerVo.getMobile())||StringUtils.isEmpty(registerVo.getPassword())||StringUtils.isEmpty(registerVo.getNicknanme()))
{
throw new GuliException(20001,"该用户不存在");
}
if(!registerVo.getCode().equals("111111"))
{
throw new GuliException(20001,"验证码错误");
}
//判断手机号是否重复
QueryWrapper<UcenterMember> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mobile",registerVo.getMobile());
Integer count = baseMapper.selectCount(queryWrapper);
if(count>0)
{
throw new GuliException(20001,"该手机账户以存在");
}
UcenterMember ucenterMember = new UcenterMember();
ucenterMember.setMobile(registerVo.getMobile());
ucenterMember.setNickname(registerVo.getNicknanme());
ucenterMember.setPassword(MD5.encrypt(registerVo.getPassword()));
ucenterMember.setIsDisabled(false);
baseMapper.insert(ucenterMember);
}
5.4获取用户token信息的接口
//根据Token获取用户信息
@GetMapping("/getMemberInfo")
public R getMemeberInfo(HttpServletRequest request)
{
//调用jwt类的方法,根据request对象获取头信息,返回用户id
String memberId = JwtUtils.getMemberIdByJwtToken(request);
//查询数据库,根据id获取用户信息
UcenterMember member = memberService.getById(memberId);
return R.ok().data("userInfo",member);
}
6. 首页面登录注册页面整合
6.1安装插件
npm install element-ui
npm install vue-qriously
6.2修改配置文件 nuxt-swiper-plugin.js,使用插件
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper/dist/ssr'
import VueQriously from 'vue-qriously'
import ElementUI from 'element-ui' //element-ui的全部组件
import 'element-ui/lib/theme-chalk/index.css'//element-ui的css
Vue.use(ElementUI) //使用elementUI
Vue.use(VueQriously)
Vue.use(VueAwesomeSwiper)
6.3 整合登录和注册页面
- 在layouts文件夹创建登录注册布局页面sign.vue
<template>
<div class="sign">
<!--标题-->
<div class="logo">
<img src="~/assets/img/logo.png" alt="logo">
</div>
<!--表单-->
<nuxt/>
</div>
</template>
- 修改登录注册超链接的地址
在layouts下面的default.vue里面修改
- 根据路由信息创建注册页面
. - 注册页面同理
6.4 注册前端整合
- 在api中创建register.js,定义注册接口的方法
import request from '@/utils/request'
export default{
//根据手机号发送验证码
sendCode(){
return request({
url: `/edumsm/msm/send/${phone}`,
method: 'GET'
})
},
//注册用户
registerMember(fromItem)
{
return request({
url:"/eudcenter/member/register",
method:"post",
data: fromItem
})
}
}
- register.vue
<template>
<div class="main">
<div class="title">
<a href="/login">登录</a>
<span>·</span>
<a class="active" href="/register">注册</a>
</div>
<div class="sign-up-container">
<el-form ref="userForm" :model="params">
<el-form-item class="input-prepend restyle" prop="nickname" :rules="[{ required: true, message: '请输入你的昵称', trigger: 'blur' }]">
<div>
<el-input type="text" placeholder="你的昵称" v-model="params.nickname"/>
<i class="iconfont icon-user"/>
</div>
</el-form-item>
<el-form-item class="input-prepend restyle no-radius" prop="mobile" :rules="[{ required: true, message: '请输入手机号码', trigger: 'blur' },{validator: checkPhone, trigger: 'blur'}]">
<div>
<el-input type="text" placeholder="手机号" v-model="params.mobile"/>
<i class="iconfont icon-phone"/>
</div>
</el-form-item>
<el-form-item class="input-prepend restyle no-radius" prop="code" :rules="[{ required: true, message: '请输入验证码', trigger: 'blur' }]">
<div style="width: 100%;display: block;float: left;position: relative">
<el-input type="text" placeholder="验证码" v-model="params.code"/>
<i class="iconfont icon-phone"/>
</div>
<div class="btn" style="position:absolute;right: 0;top: 6px;width: 40%;">
<a href="javascript:" type="button" @click="getCodeFun()" :value="codeTest" style="border: none;background-color: none">{{codeTest}}</a>
</div>
</el-form-item>
<el-form-item class="input-prepend" prop="password" :rules="[{ required: true, message: '请输入密码', trigger: 'blur' }]">
<div>
<el-input type="password" placeholder="设置密码" v-model="params.password"/>
<i class="iconfont icon-password"/>
</div>
</el-form-item>
<div class="btn">
<input type="button" class="sign-up-button" value="注册" @click="submitRegister()">
</div>
<p class="sign-up-msg">
点击 “注册” 即表示您同意并愿意遵守简书
<br>
<a target="_blank" href="http://www.jianshu.com/p/c44d171298ce">用户协议</a>
和
<a target="_blank" href="http://www.jianshu.com/p/2ov8x3">隐私政策</a> 。
</p>
</el-form>
<!-- 更多注册方式 -->
<div class="more-sign">
<h6>社交帐号直接注册</h6>
<ul>
<li><a id="weixin" class="weixin" target="_blank" href="http://huaan.free.idcfengye.com/api/ucenter/wx/login"><i
class="iconfont icon-weixin"/></a></li>
<li><a id="qq" class="qq" target="_blank" href="#"><i class="iconfont icon-qq"/></a></li>
</ul>
</div>
</div>
</div>
</template>
<script>
import '~/assets/css/sign.css'
import '~/assets/css/iconfont.css'
import registerApi from '@/api/register'
export default {
layout: 'sign',
data() {
return {
params: { //封装注册输入数据
mobile: '',
code: '', //验证码
nickname: '',
password: ''
},
sending: true, //是否发送验证码
second: 60, //倒计时间
codeTest: '获取验证码'
}
},
methods: {
//注册提交的方法
submitRegister()
{
registerApi.registerMember(this.params)
.then(response=>{
//提示注册成功
this.$message({
type:'success',
message:"注册成功"
})
.catch(err=>{
this.$message({
type:'success',
message:err
})
})
//跳转登录页面
this.$router.push({path:'/login'})
})
},
//通过输入的手机号发送验证码
getCodeFun(){
registerApi.sendCode(this.params.mobile)
.then(response=>{
this.sending=false
//调用倒计时方法
this.timeDown()
})
},
//倒计时
timeDown() {
let result = setInterval(() => {
--this.second;
this.codeTest = this.second
if (this.second < 1) {
clearInterval(result);
this.sending = true;
//this.disabled = false;
this.second = 60;
this.codeTest = "获取验证码"
}
}, 1000);
},
checkPhone (rule, value, callback) {
//debugger
// if (!(/^1[34578]\d{9}$/.test(value))) {
// return callback(new Error('手机号码格式不正确'))
// }
return callback()
}
}
}
</script>
6.5 登录前端整合
6.5.1. 在api创建login.js文件,定义接口地址
import request from '@/utils/request'
export default{
//用户登录
submitLogin(userInfo) {
return request({
url:`/eudcenter/member/logign`,
method:'post',
data:userInfo
})
},
//获取用户token
getLoginUserInfo(){
return request({
url:"/eudcenter/member/getMemberInfo",
method:'get'
})
}
}
6.5.2 在登录页面进行方法的调用
- 下载插件
npm install js-cookie
- 页面的调用
6.5.3 登录和登录成功之后首页页面显示数据实现过程分析
- 调用登录接口返回token字符串
- 把第一部返回的token字符串放在cookie里面
- 创建前端拦截器
判断cookie里面是否有token字符串,如果有吧token字符串放到header(请求头) - 根据token值调用接口,根据token获取用户信息,为了受页面显示,把调用接口返回的用户信息放在cookie里面
- 首页根据cookie获取用户信息
实现
在login.vue调用接口
在request.js中创建拦截器
修改layouts中的default.vue页面
显示登录之后的用户信息
用户退出,在layouts/index.vue中当用户点击退出按钮是清空cookie
//退出
logout(){
//情况cookie
cookie.set('guli_token','',{domain:'localhost'})
cookie.set('guli_ucenter','',{domain:'localhost'})
//返回首页面
window.location.href="/"
}
7.代码总结
login.js
import request from '@/utils/request'
export default{
//用户登录
UsersubmitLogin(userInfo) {
return request({
url:`/eudcenter/member/logign`,
method:'post',
data:userInfo
})
},
//获取用户token
getLoginUserInfo(){
return request({
url:"/eudcenter/member/getMemberInfo",
method:'get'
})
}
}
login.vue
<template>
<div class="main">
<div class="title">
<a class="active" href="/login">登录</a>
<span>·</span>
<a href="/register">注册</a>
</div>
<div class="sign-up-container">
<el-form ref="userForm" :model="user">
<el-form-item class="input-prepend restyle" prop="mobile" :rules="[{ required: true, message: '请输入手机号码', trigger: 'blur' },{validator: checkPhone, trigger: 'blur'}]">
<div >
<el-input type="text" placeholder="手机号" v-model="user.mobile"/>
<i class="iconfont icon-phone" />
</div>
</el-form-item>
<el-form-item class="input-prepend" prop="password" :rules="[{ required: true, message: '请输入密码', trigger: 'blur' }]">
<div>
<el-input type="password" placeholder="密码" v-model="user.password"/>
<i class="iconfont icon-password"/>
</div>
</el-form-item>
<div class="btn">
<input type="button" class="sign-in-button" value="登录" @click="submitLogin()">
</div>
</el-form>
<!-- 更多登录方式 -->
<div class="more-sign">
<h6>社交帐号登录</h6>
<ul>
<li><a id="weixin" class="weixin" target="_blank" href="http://qy.free.idcfengye.com/api/ucenter/weixinLogin/login"><i class="iconfont icon-weixin"/></a></li>
<li><a id="qq" class="qq" target="_blank" href="#"><i class="iconfont icon-qq"/></a></li>
</ul>
</div>
</div>
</div>
</template>
<script>
import '~/assets/css/sign.css'
import '~/assets/css/iconfont.css'
import cookie from 'js-cookie'
import loginApi from '@/api/login'
export default {
layout: 'sign',
data () {
return {
//手机号和密码
user:{
mobile:'',
password:''
},
//用户信息
loginInfo:{}
}
},
methods: {
//登录
//1. 调用接口进行登录
submitLogin(){
loginApi.UsersubmitLogin(this.user)
.then(response=>{
//2. 获取token字符串f放到cookie里面
//参数 1. cookie名称 2.参数值 参数范围
cookie.set('guli_token',response.data.data.token,{domain:'localhost'})
//4. 调用接口,根据token获取用户信息进行前端的显示
loginApi.getLoginUserInfo()
.then(response=>{
//根据用户返回的信息放入token
console.log(response.data.data.userInfo)
cookie.set('guli_ucenter',JSON.stringify(response.data.data.userInfo),{domain:'localhost'})
//页面跳转
window.location.href="/"
})
}
)
},
checkPhone (rule, value, callback) {
//debugger
// if (!(/^1[34578]\d{9}$/.test(value))) {
// return callback(new Error('手机号码格式不正确'))
// }
return callback()
}
}
}
</script>
<style>
.el-form-item__error{
z-index: 9999999;
}
</style>
register.js
import axios from 'axios'
import {MessageBox,Message} from 'element-ui'
import cookie from 'js-cookie';
//创建axios实例
const service = axios.create({
baseURL: 'http://localhost:9001',//api的base_url
timeout:20000 //请求超时时间
})
// http request 拦截器
service.interceptors.request.use(
config => {
//debugger
//判断是否存在名为guli_token的token
if (cookie.get('guli_token')) {
//把获取的cookie值放到header里面
config.headers['token'] = cookie.get('guli_token');
}
return config
},
err => {
return Promise.reject(err);
})
// http response 拦截器
service.interceptors.response.use(
response => {
//debugger
if (response.data.code == 28004) {
console.log("response.data.resultCode是28004")
// 返回 错误代码-1 清除ticket信息并跳转到登录页面
//debugger
window.location.href="/login"
return
}else{
if (response.data.code !== 20000) {
//25000:订单支付中,不做任何提示
if(response.data.code != 25000) {
Message({
message: response.data.message || 'error',
type: 'error',
duration: 5 * 1000
})
}
} else {
return response;
}
}
},
error => {
return Promise.reject(error.response) // 返回接口返回的错误信息
});
export default service
register.vue
<template>
<div class="main">
<div class="title">
<a href="/login">登录</a>
<span>·</span>
<a class="active" href="/register">注册</a>
</div>
<div class="sign-up-container">
<el-form ref="userForm" :model="params">
<el-form-item class="input-prepend restyle" prop="nickname" :rules="[{ required: true, message: '请输入你的昵称', trigger: 'blur' }]">
<div>
<el-input type="text" placeholder="你的昵称" v-model="params.nickname"/>
<i class="iconfont icon-user"/>
</div>
</el-form-item>
<el-form-item class="input-prepend restyle no-radius" prop="mobile" :rules="[{ required: true, message: '请输入手机号码', trigger: 'blur' },{validator: checkPhone, trigger: 'blur'}]">
<div>
<el-input type="text" placeholder="手机号" v-model="params.mobile"/>
<i class="iconfont icon-phone"/>
</div>
</el-form-item>
<el-form-item class="input-prepend restyle no-radius" prop="code" :rules="[{ required: true, message: '请输入验证码', trigger: 'blur' }]">
<div style="width: 100%;display: block;float: left;position: relative">
<el-input type="text" placeholder="验证码" v-model="params.code"/>
<i class="iconfont icon-phone"/>
</div>
<div class="btn" style="position:absolute;right: 0;top: 6px;width: 40%;">
<a href="javascript:" type="button" @click="getCodeFun()" :value="codeTest" style="border: none;background-color: none">{{codeTest}}</a>
</div>
</el-form-item>
<el-form-item class="input-prepend" prop="password" :rules="[{ required: true, message: '请输入密码', trigger: 'blur' }]">
<div>
<el-input type="password" placeholder="设置密码" v-model="params.password"/>
<i class="iconfont icon-password"/>
</div>
</el-form-item>
<div class="btn">
<input type="button" class="sign-up-button" value="注册" @click="submitRegister()">
</div>
<p class="sign-up-msg">
点击 “注册” 即表示您同意并愿意遵守简书
<br>
<a target="_blank" href="http://www.jianshu.com/p/c44d171298ce">用户协议</a>
和
<a target="_blank" href="http://www.jianshu.com/p/2ov8x3">隐私政策</a> 。
</p>
</el-form>
<!-- 更多注册方式 -->
<div class="more-sign">
<h6>社交帐号直接注册</h6>
<ul>
<li><a id="weixin" class="weixin" target="_blank" href="http://huaan.free.idcfengye.com/api/ucenter/wx/login"><i
class="iconfont icon-weixin"/></a></li>
<li><a id="qq" class="qq" target="_blank" href="#"><i class="iconfont icon-qq"/></a></li>
</ul>
</div>
</div>
</div>
</template>
<script>
import '~/assets/css/sign.css'
import '~/assets/css/iconfont.css'
import registerApi from '@/api/register'
export default {
layout: 'sign',
data() {
return {
params: { //封装注册输入数据
mobile: '',
code: '', //验证码
nickname: '',
password: ''
},
sending: true, //是否发送验证码
second: 60, //倒计时间
codeTest: '获取验证码'
}
},
methods: {
//注册提交的方法
submitRegister()
{
registerApi.registerMember(this.params)
.then(response=>{
//提示注册成功
this.$message({
type:'success',
message:"注册成功"
})
//跳转登录页面
this.$router.push({path:'/login'})
})
},
//通过输入的手机号发送验证码
getCodeFun(){
registerApi.sendCode(this.params.mobile)
.then(response=>{
this.sending=false
//调用倒计时方法
this.timeDown()
})
},
//倒计时
timeDown() {
let result = setInterval(() => {
--this.second;
this.codeTest = this.second
if (this.second < 1) {
clearInterval(result);
this.sending = true;
//this.disabled = false;
this.second = 60;
this.codeTest = "获取验证码"
}
}, 1000);
},
checkPhone (rule, value, callback) {
//debugger
// if (!(/^1[34578]\d{9}$/.test(value))) {
// return callback(new Error('手机号码格式不正确'))
// }
return callback()
}
}
}
</script>