go语言之路

一起来捋一捋前后端分离登录过程的思路并实现全过程

一起来捋一捋前后端分离登录过程的思路并实现全过程

本文将实现前后端分离开发模式下的登录过程

需要使用到的技术栈为:

  • go/java web框架(gin/springboot)
  • mysql orm框架(gorm/mybatis)
  • vue(前端框架)

看似不起眼的登录其实还是有很多值得探讨的地方

在保证安全的情况也也要增加用户的体验

现在的开发中一般都采用前后端分离的模式

采用jwt token进行鉴权

若token失效,此时需要重新登录

并且调用其他请求时,请求头中必须携带token

从一定程度上保证了安全性

关于登录的流程分为以下几步

  • 用户输入用户名和密码并登录(即提交表单)
  • 后端查询数据库,验证用户名于密码是否匹配,若匹配,返回token给前端
  • 前端登录,进入到主页面(/view.html),并将token存在localStorage中(若对安全性要求高,不建议存在本地,应当使用Redis进行存储)
  • 若用户没有登录直接输入/view.html,重定向到登录页(根据localStorage中的token判断)
  • 登录之后每次请求时请求头中携带token,后端会对token进行检验
  • 若token无效或者过期,后端返回错误码,如401,前端将页面重定向到登录页重新登录

开发流程(使用go web框架和Vue进行示范)

后端

定义一个model

并把Username作为主键

type Login struct {

    Username string `json:"username" gorm:"primaryKey"`

    Password string `json:"password"`

}

连接数据库,拿到db

db, err := gorm.Open(mysql.Open(path))

初始化数据库

db.AutoMigrate(&Login{})

使用ORM,我们不需要去手动创建表,创建字段

对于golang和ORM框架来说,struct就可以看做是数据库中的表

struct中的属性可以看做是表中的字段

db.AutoMigrate(&Login{}),将会在数据库中自动绑定表,并创建相应的字段

编写service

func TrueLogin(username, password string) (string, error) {

    var login Login 

    //根据前端传来的username,进行查询
    err := db.Where("username = ?", username).Find(&login).Error

    if err != nil {

        //如果没有查询到,则返回用户名或者密码错误
        return "", errors.New("The password is incorrect")

    }

    //判断前端传过来的用户名是否与查询到的用户名是否相同,这一步可有可无,因为肯定是相同的
    //判断用户传过来的密码是否与查询到的用户的密码是否相同
    if username == login.Username && password == login.Password {

        //校验成功之后使用中间件生成token并返回
        tokenString, _ := middlewares.GenToken(login.Username, login.Password)

        return tokenString, nil

    } else {

        //否则提示用户名/密码错误
        return "", errors.New("The password is incorrect")
    }
}

参数为username和password,由controller层进行获取

service只用进行逻辑判断,对传进来的username和password进行校验

检验成功后返回token,检验不成功则返回相关的错误信息

编写controller

func TrueLogin(c *gin.Context) {

    //c.PostForm用于POST请求时, 获取表单的值
    username := c.PostForm("username")

    password := c.PostForm("password")

    //将username和password传到service进行校验
    tokenString, err := service.TrueLogin(username, password)

    if err != nil {
        //返回json
        // {"code":200, "message":"用户名不存在或者密码不正确"}
        //
        c.IndentedJSON(200, gin.H{
            "code":2002,
            "message":err,
        })

    } else {

        c.IndentedJSON(http.StatusOK, gin.H{
            //返回json
            // {"code":200, "message":"login successfully", "data":tokenString}
            "code":2002,
            "message":"login successfully",
            "data":tokenString,
        })
    }
}

编写router路由

func LoadLogin(e *gin.Engine) {
    e.POST("/api/v3/trueLogin", controllers.TrueLogin)
}

运行并制定端口

err := r.Run(":8080")

此时该服务便可以通过http://localhost:8080/api/v3/tureLogin进行访问

测试

假设表中有一条数据

username = test

password = test

image-20210104203628160

image-20210104203828202

使用Vue

使用axios请求后端

将input输入框的数据提交到后台

后台并返回结果

前端对后端返回的结果进行判断

若为"login successfully"

则登录成功并跳转到hello.html并将后端返回的token保存到localStorage中

否则提示用户名/密码错误

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>login</title>
</head>
<body>

  <div id="app"> 
    <input type="text" v-model="loginForm.username" placeholder="用户名"/>
    <input type="text" v-model="loginForm.password" placeholder="密码"/>
    <button @click="login">登录</button>
  </div>

  <script src="./js/vue.js"></script>
  <script src="./js/axios.min.js"></script>
  <script>
    var vue = new Vue({
      el:"#app",
      data: {
        loginForm:{
          username:'',
          password:''
        }
      },
      methods : {
      login (){
        let param = new URLSearchParams()
        param.append('username', this.loginForm.username)
        param.append('password', this.loginForm.password)
        axios ({
          method:'post',
          url:"http://nj-jay.com:8080/api/v3/trueLogin",
          data:param
        }).then(function(response){
          console.log(response.data)
          //window.location.href = 'http://47.97.44.29:8000'
          if (response.data.message=="login successfully"){
            alert("登录成功")
            //登录成功就跳转
            window.location.href = 'hello.html';
            var user_token = response.data.data;
            // 存token到localStorage中
            localStorage.setItem("currentUser_token", user_token);
          } else {
              alert("用户名/密码错误")
          }
        })
      }
    }
  })
  </script>
</body>
</html>

在hello.html中head标签中嵌入checkLog函数判断localStorage中是否存在token

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <script src="./js/function.js"></script>
  <script type="text/javascript">checkLog()</script>
  <title>about</title>
</head>
<body>

  <h1>welcome</h1>

  <script src="./js/vue.js"></script>
  <script src="./js/axios.min.js"></script>
</body>
</html>

function.js

判断localStorage中是否存在token

若不存在则跳转到登录页

function checkLog(){
    var a = localStorage.getItem('currentUser_token')
    if (!a) {
        //不存在就跳转到首页
        window.location.href = './index.html'
    }
  }

以上就是登录实现的所有过程

完整代码示例包含在我的github中

链接: https://github.com/nj-jay/mysql-gin-api

欢迎star

技术的产生是要用来解决实际问题的,首要工作是要把实际问题弄明白

上一篇

如何使用前后端统计页面的访问量?

下一篇

你也可能喜欢

1 条评论

发表评论

您的电子邮件地址不会被公开。 必填项已用 * 标注

提示:点击验证后方可评论!

插入图片

个人微信公众号

we-tuiguang

qq交流群

群号:1046260719

微信扫一扫

微信扫一扫