1. 程式人生 > 其它 >基於gin框架的登入註冊

基於gin框架的登入註冊

包含前端vue,後端gin框架的登入註冊以及mysql資料庫的連線使用,主要是練習後端框架的使用,前端簡陋見諒。
一.前端vue部分
首先搭建vue框架,可以參考我的這篇部落格https://blog.csdn.net/m0_49049914/article/details/112527510
前端登入頁面展示如下

在這裡插入圖片描述
程式碼如下:主要是使用的vant元件庫

<template>
  <div>
    <van-form @submit="onSubmit">
      <van-field
        v-model="username"
name="username" label="賬號" placeholder="賬號" :rules="[{ required: true, message: '請填寫賬號' }]" /> <van-field v-model="password" type="password" name="password"
label="密碼" placeholder="密碼" :rules="[{ required: true, message: '請填寫密碼' }]" /> <div style="margin: 16px;"> <van-button round block type="info" native-type="submit">登入</van-button>
<van-button type="primaty" to="signup">註冊</van-button> </div> </van-form> </div> </template> <script> import { login } from "../api/login"; import Cookies from 'js-cookie' // import { login1 } from "../api/login"; export default { data() { return { username: "", password: "" } }, methods: { async onSubmit(values) { var _this = this console.log("submit", values); await login(values).then(function(res) { if(res.data.code == 2000) { Cookies.set('token', res.data.data.token) _this.$router.replace("/list") } else { alert("賬號或密碼錯誤") } }); } } }; </script>

裡面用到的知識有:後端介面的呼叫,cookie的設定,以及前後端互動
二.介面呼叫

import request from '../../utils/request'


export function login(param) {
    return request({
        url:'v1/login',
        method:'post',
        data: param,
    })
}

request.js檔案如下:

import axios from 'axios'
import { getToken } from './auth'
import Cookies from 'js-cookie'
import Config from '../settings'
import qs from 'qs'

// 建立axios例項
const service = axios.create({
    baseURL: Config.baseURL, // api 的 base_url
    timeout: Config.timeout // 請求超時時間
});

// request攔截器
service.interceptors.request.use(
    config => {
        if (getToken()) {
            config.headers['Authorization'] = "Bearer "+getToken() //讓每個請求攜帶自定義token
                // config.headers['Authorization'] = 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIzMGQ2NjU2Y2YwZTA0ZTFhODQ2Y2Q2ZGE0OTBhZmJlOCIsImF1dGgiOiJhZG1pbiIsInN1YiI6ImFkbWluIn0.owHaRwQYsSIBb8h5EjABbNsmNnjefVGemuR51iTdWw5cZDuwMd6BKzc5_RyV8STBZyPO_krte4qRZb3-D_n6zQ'; //讓每個請求攜帶自定義token
        }
        config.headers['Content-Type'] = Config.contentType;
        console.log(config.data,"ddddawdawd")
        //對引數進行qs的序列化
        config.data = JSON.stringify(config.data);
        console.log(config.data,"ddddawdawd")
        return config;
    },
    error => {
        // 對請求錯誤做些什麼,自己定義
        //...
        return new Promise(function(resolve, reject) {
            reject(error);
        }).catch(function(reason) {
            console.log('catch:', reason);
        });
    }
);
// response 攔截器
service.interceptors.response.use(

    response => {
        console.log(response.status);
        if (response.status === 200) {
            return Promise.resolve(response);
        } else {
            return new Promise(function(resolve, reject) {
                reject(response);
            }).catch(function(reason) {
                console.log('catch:', reason);
            });
        }
    },
    error => {
        if (error.response.data.status === 401) {
            console.log(123);
            Cookies.remove('TOEKN');
        }
        let code = 0;
        let message = error.response.data.message;
        //網路請求超時
        try {
            code = error.response.status;
        } catch (e) {
            if (error.toString().indexOf('Error: timeout') !== -1) {
                //...
                return new Promise(function(resolve, reject) {
                    reject(error);
                }).catch(function(reason) {
                    console.log('catch:', reason);
                });
            }
        }
        //其它有狀態碼的返回情況
        if (code) {
            return new Promise(function(resolve, reject) {
                    reject(message);
                })
                // .catch(function(reason) {
                // 	console.log('catch:', reason);
                // });
        }
        //網路斷開情況
        if (error.toString().indexOf('Error: Network Error') !== -1) {
            //...
            return new Promise(function(resolve, reject) {
                reject(error);
            }).catch(function(reason) {
                console.log('catch:', reason);
            });
        }
        //其他情況
        //...
        return new Promise(function(resolve, reject) {
            reject(error);
        }).catch(function(reason) {
            console.log('catch:', reason);
        });
    }
);
export default service

在這裡注意解決跨域問題,只需要在後端新增一個跨域中介軟體即可。
程式碼如下:

package middleware

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
)

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		fmt.Println(method)
		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, PATCH, DELETE")
		c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
		c.Header("Access-Control-Allow-Credentials", "true")

		// 放行所有OPTIONS方法,因為有的模板是要請求兩次的
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}

		// 處理請求
		c.Next()
	}
}

三.進行mysql資料庫連線並建立表
在這裡我建了兩張表

package Mysql

import (
  _ "github.com/go-sql-driver/mysql"
  "github.com/jinzhu/gorm"
)

type People struct {
  ID        uint                      `gorm:"primary_key" json:"id" db:"user_id"`
  Account   string                    `json:"account"`
  Password string                     `json:"password"  binding:"required" db:"password"`
  Signature string                    `json:"signature"`
  Username  string                    `json:"username"  binding:"required" db:"username"`
  Speaks []Speak                      `json:"speaks"`
}

type Speak struct {
  gorm.Model
  PeopleId uint
  Content string
  Path string
}
  var DB *gorm.DB
func Mysql1() (err error){
  DB,_ = gorm.Open("mysql","root:[email protected](localhost)/gin_demo?charset=utf8&parseTime=True&loc=Local")
  DB.AutoMigrate(&People{},&Speak{})
  return err
}

四.後端登入操作
controller層分為三部分:1.獲取引數和引數校驗 2.業務處理 3.返回響應

//登入
func LoginHandler(c *gin.Context){
	//1.獲取引數和引數校驗
	p := new(models.ParamLogin)
	//shouldbindjson只能檢測型別對不對,是不是Json格式
	if err := c.ShouldBindJSON(&p);err != nil {
		//請求引數有誤,直接返回響應
		c.JSON(http.StatusOK, gin.H{
			"msg": "請求引數有誤",
		})
		return
	}
	//2.業務處理
	if err := logic.Login(p);err != nil{
		c.JSON(http.StatusOK,gin.H{
			"msg":"使用者名稱或密碼錯誤",
			"err" : err,
		})
		return
	}

		//生成token
		tokenString,_ := GenToken(p.Username)
		c.JSON(http.StatusOK,gin.H{
			"code":2000,
			"msg":"success",
			"data":gin.H{"token":tokenString},
		})
		return

	//3.返回響應
	c.JSON(http.StatusOK,gin.H{
		"code":2000,
		"msg":"登入成功",
	})
}

在登入成功後會生成token,並存儲到cookie中,介紹完登入操作後,在進行token的操作

func Login(p *models.ParamLogin) error {
	err := Mysql.Login(p)
	if err != nil {
		return err
	}
	return nil

}
type PWD struct {
	Password string
}
func Login(user *models.ParamLogin) (err error) {
	pwd := new(PWD)
	err = DB.Table("peoples").Select("password").Where("username=?", user.Username).First(pwd).Error
	if err == sql.ErrNoRows{
		fmt.Println(err)
		return errors.New("使用者不存在")
	}
	if err != nil{
		//查詢資料庫失敗
		return err
	}
	//判斷密碼是否正確
	if user.Password != pwd.Password{
		err = errors.New("密碼錯誤")
		return err
	}
	return nil
}

注意:從資料庫中取資料時:先把前端傳送過來的資訊取出來賦值給一個結構體和資料庫中的資料去做對比,首次登入如何把密碼使用者名稱傳給後臺,傳給後臺和資料庫裡的資料做對比,之後生成token,儲存到cookie或localstorage中,localstorage是永久儲存,cookie可以設定過期時間

接下來展示生成token的方式:


type MyClaims struct {
	Username string  `json:"username"`
	jwt.StandardClaims
}

type UserInfo struct {
	Username string    `json:"username"`
	Password string    `json:"password"`
}

//GenToken生成JWT
func GenToken(username string) (string,error)  {
	mySigningKey := []byte("woshiadminfangguowoba")
	d := MyClaims{
		Username: username,
		StandardClaims:jwt.StandardClaims{
			NotBefore: time.Now().Unix() - 60,      //生效時間
			ExpiresAt: time.Now().Unix() + 60*60*2,  //過期時間
			Issuer: "admin",                        //簽發人
		},
	}
	t := jwt.NewWithClaims(jwt.SigningMethodHS256,d)
	s,e := t.SignedString(mySigningKey)          //對token進行加密
	if e!=nil{
		fmt.Printf("&s",e)
	}
	return s,e
}


五.展示註冊介面
在這裡插入圖片描述
和登入的操作沒有太大的差別。

//註冊
func SignupHandler(c *gin.Context)  {
	p1 := new(models.ParamSignup)
	if err := c.ShouldBindJSON(&p1);err != nil{
		c.JSON(http.StatusOK,gin.H{
			"msg":"請求引數錯誤",
		})
		return
	}
	//2.業務處理1
	if err := logic.Signup(p1);err != nil{
		c.JSON(http.StatusOK,gin.H{
			"err" : err,
			"msg" : "註冊失敗",
			"code":8888,
		})
		return
	}
	//3.返回響應
	c.JSON(http.StatusOK,gin.H{
		"code":0,
		"msg":"註冊成功",
	})
}

func Signup(p1 *models.ParamSignup) (err error)  {
	//1.判斷使用者存不存在
	var exist bool
	exist,err = Mysql.CheckUserExist(p1.Username)
	if err != nil{
		return err
	}
	if exist{
		return errors.New("使用者已存在")
	}
	err = Mysql.InsertUser(p1)
	if err != nil{
		return err
	}
	return nil
}
//註冊時先檢驗使用者是否已經存在
func CheckUserExist(username string)(bool,error)  {
	var p2 []People
	DB.Find(&p2,"username=?",username)
	var count int
	count = len(p2)
	return count > 0,nil
}
//註冊時將使用者資訊儲存到資料庫中
func InsertUser(user *models.ParamSignup) (err error) {
	DB.Create(&People{
		Username: user.Username,
		Password: user.Password,
		Signature: user.Signature,
		Account: user.Account,
	})
	if err != nil{
		return err
	}
	return nil
}

第一次自己獨立的去完成gin框架,其中遇到了很多問題,有很多人都在幫助我,歷時很多天完成了這些,收穫很大!!!加油!!!