vue前后端分离 用户注册 登录拦截

vue登陆拦截初体验

也是第一次做vue前后端分离 用户注册 登录拦截。项目已经搭建完成,下面分享一下搭建过程。

前端vue

1.login界面
在这里插入图片描述
2.注册页面
在这里插入图片描述
3.展示页面
在这里插入图片描述

前台页面在element官网组件有详细教程,这里不再赘诉。主要还是后台逻辑的实现不是嘛,哈哈。

逻辑分析

1.登陆
前台vue将user对象传到controller层,在service里处理相关业务逻辑:

public ServerResponse login(User user , HttpSession session) {
        //通过 用户名获取数据库用户
        User userByName = userMapper.findUserByName(user.getName());
        if(userByName==null){//无法通过用户名获取数据库用户,即用户不存在
            return ServerResponse.error("用户不存在");
        }
        //通过数据库用户,获得salt,然后将前台的user的密码加salt,然后md5两次加密后和数据库的密码匹配
        String pwd = MD5Util.getPwd(MD5Util.getPwd(user.getPassword() + userByName.getSalt()));
        if(!pwd.equals(userByName.getPassword())){//密码匹配失败
            return ServerResponse.error("密码错误");
        }
        //用户名,密码验证成功,放入session中
        session.setAttribute(SystemConstant.SESSION_KEY,userByName);

        return ServerResponse.success();
    }

2.注册
注册要验证用户名是否已存在,而且两次密码要相同,那么很舒服的是element官网提供了我们验证表单的代码,要学会粘贴修改使用它即可。
当填写用户名是,有一个blur失去焦点事件,当触发该事件时要调用后台的根据名称查询用户的方法。

public ServerResponse findUserByName(String name) {
        User user = userMapper.findUserByName(name);
        if(user == null){
            return ServerResponse.success();
        }

        return ServerResponse.error();
    }

当用户名,密码有问题时,表单不允许提交。然后将用户名和验证好的密码传入后台。

public ServerResponse register(User user) {
        //为确保密码安全性,给密码加盐
        String salt = RandomStringUtils.randomAlphanumeric(20);
        //为确保密码安全性,两次MD5加密
        String pwd = MD5Util.getPwd(MD5Util.getPwd(user.getPassword() + salt));
        user.setCreateDate(new Date());
        //将盐保存数据库,只有对应的密码和对应的盐在一起才会生成正确的密码
        user.setSalt(salt);
        user.setPassword(pwd);
        //新增用户
        userMapper.register(user);
        return ServerResponse.success();
    }

现有的坑

1.前后端分离,跨域问题?
2.前后端分离,cookies无法传到后台?
3.后端返回对应状态码时,前端怎么把对应的状态码转换跳转到对应的页面?
4.登录拦截怎么实现?

1.前后端分离,跨域问题?
通过后台的拦截器方法,每当请求controller层方法时,都要走拦截器类,
在拦截器类解决跨域问题:

 //跨域
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,"http://localhost:9090");
        response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,"x-auth,content-type,mtoken");
        response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,"PUT,POST,DELETE,GET");
        response.addHeader("Access-Control-Allow-credentials","true");

2.前后端分离,cookies无法传到后台?
z在前台vue项目中 main.js 配置
axios.defaults.withCredentials = true
在这里插入图片描述

3.后端返回对应状态码时,前端怎么把对应的状态码转换跳转到对应的页面?
z在前台vue项目中 main.js 配置 前台拦截器:
在这里插入图片描述
对比状态码,通过location跳转指定页面。

4.登录拦截怎么实现?
首先我们要知道,有些方法是不能拦截的。所有要配置白名单,之前在登陆拦截的csdn里已经介绍过一种方法,现在介绍另一种方法。
我自定义一个注解,

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Ignore {
}

通过该注解可以选择性过滤一些方法不拦截。
具体实现如下:

 HandlerMethod handlerMethod= (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        if(method.isAnnotationPresent(Ignore.class)){
            return true;
        }

只要在我写过的方法上加上ignore了,方法就可以通通return true;
当我的session中没有user时就意味着登陆失败,那就要抛出一个我自定义的异常,返回给前台一个code,通过判断该code跳转页面。

@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //跨域
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,"http://localhost:9090");
        response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,"x-auth,content-type,mtoken");
        response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,"PUT,POST,DELETE,GET");
        response.addHeader("Access-Control-Allow-credentials","true");

        //拦截器白名单
        HandlerMethod handlerMethod= (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        if(method.isAnnotationPresent(Ignore.class)){
            return true;
        }
        User user = (User) request.getSession().getAttribute(SystemConstant.SESSION_KEY);
        if(user != null){
            return true;
        }else{
            throw new LoginException();
        }

    }

LoginException如下:
在这里插入图片描述
全局异常捕获。

全部代码

1.登陆vue:

<template>
    <div style="margin-left: 35%; margin-top: 10%">
      <el-form ref="user" :model="user" label-width="80px">
        <el-form-item label="用户名" style="width: 260px">
          <el-input v-model="user.name"></el-input>
        </el-form-item>
        <el-form-item label="密码" style="width: 260px">
          <el-input type="password" v-model="user.password"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" size="small" @click="onSubmit" style="margin-left: 20px; margin-top: 20px">登陆</el-button>
          <el-link type="primary" style="margin-left: 20px;" href="/register">注册</el-link>
        </el-form-item>
      </el-form>
    </div>
</template>

<script>
    export default {
        name: "login",
      data() {
        return {
          user: {
            name: '123',
            password: '123'
          }
        }
      },
      methods: {
        onSubmit() {
          var self = this;
          this.$axios.post("http://localhost:8085/user/login.do",this.$qs.stringify(this.user)).then(function(res){
            if(res.data.code==200){
              self.$router.push('/product');
              alert("登陆成功");
            }else{
              alert(res.data.data);
            }
          })
        }
      }
    }
</script>

<style scoped>

</style>

2.注册

<template>
    <div style="margin-left: 35%; margin-top: 10%">
      <el-form :model="user" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
        <el-form-item label="用户名" prop="name" style="width:300px">
          <el-input v-model.number="user.name"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password" style="width: 300px">
          <el-input type="password" v-model="user.password" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="确认密码" prop="checkPass" style="width: 300px">
          <el-input type="password" v-model="user.checkPass" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
          <el-button @click="resetForm('ruleForm')">重置</el-button>
        </el-form-item>
      </el-form>

    </div>
</template>

<script>
    export default {
        name: "register",
      data() {
        var checkName = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请输入用户名'));
          } else {
            if (this.user.name !== '') {
              var self = this;
              this.$axios.post("http://localhost:8085/user/findUserByName.do",this.$qs.stringify({"name":this.user.name})).then(function(res){
                if(res.data.code==200){
                  callback();
                }else{
                  callback(new Error('用户名已存在'));
                }
              })
            }

          }

        };
        var validatePass = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请输入密码'));
          } else {
            if (this.user.checkPass !== '') {
              this.$refs.ruleForm.validateField('checkPass');
            }
            callback();
          }
        };
        var validatePass2 = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请再次输入密码'));
          } else if (value !== this.user.password) {
            callback(new Error('两次输入密码不一致!'));
          } else {
            callback();
          }
        };
        return {
          user: {
            password: '',
            checkPass: '',
            name: ''
          },
          rules: {
            pass: [
              { validator: validatePass, trigger: 'blur' }
            ],
            checkPass: [
              { validator: validatePass2, trigger: 'blur' }
            ],
            name: [
              { validator: checkName, trigger: 'blur' }
            ]
          }
        };
      },
      methods: {
        submitForm(formName) {
          this.$refs[formName].validate((valid) => {
            if (valid) {
              var self = this;
              this.$axios.post("http://localhost:8085/user/register.do",this.$qs.stringify(this.user)).then(function(res){
                if(res.data.code==200){
                  self.$router.push('/');
                  alert("注册成功");
                }else{
                  alert("注册失败");
                }
              })
            } else {
              console.log('error submit!!');
              return false;
            }
          });
        },
        resetForm(formName) {
          this.$refs[formName].resetFields();
        }
      }
    }
</script>

<style scoped>

</style>

3.service层
package com.fh.service.impl;

import com.fh.common.ServerResponse;
import com.fh.mapper.UserMapper;
import com.fh.model.User;
import com.fh.service.UserService;
import com.fh.util.MD5Util;
import com.fh.util.SystemConstant;
import com.qcloud.cos.utils.Md5Utils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;

@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
public ServerResponse findUserByName(String name) {
User user = userMapper.findUserByName(name);
if(user == null){
return ServerResponse.success();
}

    return ServerResponse.error();
}

public ServerResponse register(User user) {
    //为确保密码安全性,给密码加盐
    String salt = RandomStringUtils.randomAlphanumeric(20);
    //为确保密码安全性,两次MD5加密
    String pwd = MD5Util.getPwd(MD5Util.getPwd(user.getPassword() + salt));
    user.setCreateDate(new Date());
    //将盐保存数据库,只有对应的密码和对应的盐在一起才会生成正确的密码
    user.setSalt(salt);
    user.setPassword(pwd);
    //新增用户
    userMapper.register(user);
    return ServerResponse.success();
}

public ServerResponse login(User user , HttpSession session) {
    //通过 用户名获取数据库用户
    User userByName = userMapper.findUserByName(user.getName());
    if(userByName==null){//无法通过用户名获取数据库用户,即用户不存在
        return ServerResponse.error("用户不存在");
    }
    //通过数据库用户,获得salt,然后将前台的user的密码加salt,然后md5两次加密后和数据库的密码匹配
    String pwd = MD5Util.getPwd(MD5Util.getPwd(user.getPassword() + userByName.getSalt()));
    if(!pwd.equals(userByName.getPassword())){//密码匹配失败
        return ServerResponse.error("密码错误");
    }
    //用户名,密码验证成功,放入session中
    session.setAttribute(SystemConstant.SESSION_KEY,userByName);

    return ServerResponse.success();
}

}

4.全局异常处理

package com.fh.common;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalException {

    @ExceptionHandler(MyException.class)
    public ServerResponse HandlerMyException (){
        return ServerResponse.error();
    }

    @ExceptionHandler(LoginException.class)
    public ServerResponse HandlerMyLoginException (){
        return ServerResponse.error_login();
    }

    @ExceptionHandler(Exception.class)
    public ServerResponse HandlerException (){
        return ServerResponse.error();
    }

}

5.自定义注解

package com.fh.common;

import java.lang.annotation.*;

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Ignore {
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章