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 {
}

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