详解Go-JWT-RESTful身份认证教程

详解Go-JWT-RESTful身份认证教程

介绍

本文将详细介绍如何使用Go语言实现一套基于JWT(JSON Web Token)的RESTful身份认证系统。RESTful是一种基于HTTP协议、符合REST原则的接口设计风格,使用JWT进行身份认证和授权可以轻松实现API的状态无关性和安全性。

实现步骤

生成JWT Token

生成JWT Token是RESTful身份认证系统的第一步。JWT Token可以在身份验证后与请求一起发送到API端点。Token包含已验证用户的信息,以及一些指定的元数据,并且这些元数据是经过数字签名的。我们可以使用golang-jwt库来生成JWT Token,具体操作如下:

import (
    "github.com/dgrijalva/jwt-go"
)

type User struct {
    UserID int
    Name string
    Email string
}

func generateJWT(user *User, privateKey []byte) (string, error) {
    token := jwt.New(jwt.SigningMethodHS256)
    claims := token.Claims.(jwt.MapClaims)
    claims["userID"] = user.UserID
    claims["name"] = user.Name
    claims["email"] = user.Email
    tokenString, err := token.SignedString(privateKey)
    if err != nil {
        return "", err
    }

    return tokenString, nil
}

将上述代码复制到项目中并进行一些必要的修改,例如:对传递进来的privateKey变量进行替换。

在上述代码中,我们先创建一个JWT Token对象,使用HS256算法对Token进行签名。我们还设置了一些已验证用户的信息。最后,我们使用私钥对Token进行签名,在调用SignedString函数时,私钥会自动应用于Token签名。最终,通过generateJWT函数返回的Token String将用于与其他API请求一起发送到API端点。

验证JWT Token

使用RESTful身份认证系统时,一旦JWT Token发出,接下来的步骤就是在每个请求上对Token进行验证,以确保Token还是有效的,且未被更改或伪造。在Go语言中,我们可以使用以下代码进行JWT Token验证:

import (
    "github.com/dgrijalva/jwt-go"
)

func validateJWT(tokenString string, secretKey []byte) (*User, error) {
    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
        }
        return secretKey, nil
    })

    if err != nil {
        return nil, err
    }

    if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
        user := &User{
            UserID: claims["userID"].(int),
            Name: claims["name"].(string),
            Email: claims["email"].(string),
        }

        return user, nil
    }

    return nil, fmt.Errorf("Invalid token")
}

在上述代码中,我们使用jwt.Parse函数进行Token解析,为了确保Token有效,我们首先检查Token是否是经过HS256算法签名的。接下来,我们使用提供的私钥对Token进行验证。如果Token在验证过程中是有效的,并包含所需的元数据,则我们可以创建一个User对象并返回它。如果Token无效,或者不包含所需的元数据,则将返回“Invalid token”错误消息。

实现RESTful API

有了JWT Token的生成和验证方法后,我们现在来介绍如何实现RESTful身份认证系统。在Go语言中,可以使用gofiber库来构建RESTful API。在下面的示例中,我们将展示一个基于gofiber的RESTful API,该API仅向被身份验证的用户提供访问权限。

import (
    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()

    api := app.Group("/api")
    api.Use(authenticate)

    api.Get("/user", getCurrentUser)

    app.Listen(":3000")
}

func authenticate(c *fiber.Ctx) error {
    tokenString := c.Get("Authorization")
    if tokenString == "" {
        return fiber.ErrUnauthorized
    }

    tokenString = strings.TrimPrefix(tokenString, "Bearer ")
    user, err := validateJWT(tokenString, []byte("secretKey"))
    if err != nil {
        return fiber.ErrUnauthorized
    }

    c.Locals("user", user)
    return c.Next()
}

func getCurrentUser(c *fiber.Ctx) error {
    user := c.Locals("user").(*User)
    return c.JSON(user)
}

在上述代码中,我们首先创建了一个名为api的组,它的URL前缀是/api,并使用了authenticate中间件进行身份认证。我们将getCurrentUser函数作为响应API请求的控制器。
authenticate函数中,我们使用validateJWT函数解析并验证Bearer Token(也就是JWT Token)。如果验证成功,则在请求全局对象(也就是CTX对象)中将已验证的用户对象存储为Locals,以便其他随后的请求处理函数使用。

注意,在实际应用程序中,您需要将密钥保存在数据库中,并在每个请求上使用该密钥进行Token验证。

示例

示例1

我们可以通过使用以下cURL命令来测试我们的RESTful API:

curl -H "Authorization: Bearer <Token String>" http://localhost:3000/api/user

这将返回当前用户的信息。如果令牌无效,则API将返回401(Unauthorized)错误消息。

示例2

下面是如何使用Go语言实现一个基于RESTful身份认证系统的网站:

package main

import (
    "fmt"
    "html/template"
    "log"
    "net/http"

    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()

    app.Static("/static", "./static")

    app.Get("/", home)
    app.Post("/authenticate", authenticate)
    app.Get("/dashboard", dashboard)

    app.Listen(":3000")
}

func home(c *fiber.Ctx) error {
    return c.Render("index", nil)
}

func dashboard(c *fiber.Ctx) error {
    user := c.Locals("user").(*User)
    return c.Render("dashboard", struct{ User *User }{User: user})
}

func authenticate(c *fiber.Ctx) error {
    email := c.FormValue("email")
    password := c.FormValue("password")
    user, err := validateUser(email, password)
    if err != nil {
        return c.Render("index", struct{ Error string }{Error: "Invalid email or password"})
    }

    token, err := generateJWT(user, []byte("secretKey"))
    if err != nil {
        return c.Render("index", struct{ Error string }{Error: "Failed to generate token"})
    }

    c.Cookie(&fiber.Cookie{
        Name:  "jwt",
        Value: token,
    })

    return c.Redirect("/dashboard")
}

func validateUser(email string, password string) (*User, error) {
    // validate user's credentials
}

type User struct {
    UserID int
    Name   string
    Email  string
}

type TemplateFactory struct {
    Templates map[string]*template.Template
}

func (tf *TemplateFactory) Get(name string) (*template.Template, error) {
    if t := tf.Templates[name]; t != nil {
        return t, nil
    }

    t, err := template.ParseFiles(fmt.Sprintf("%s.html", name))
    if err != nil {
        return nil, err
    }

    tf.Templates[name] = t
    return t, nil
}

func NewTemplateFactory() *TemplateFactory {
    return &TemplateFactory{
        Templates: make(map[string]*template.Template),
    }
}

func init() {
    tf := NewTemplateFactory()

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        t, err := tf.Get("index")
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        t.Execute(w, nil)
    })

    http.HandleFunc("/authenticate", func(w http.ResponseWriter, r *http.Request) {
        email := r.PostFormValue("email")
        password := r.PostFormValue("password")
        user, err := validateUser(email, password)
        if err != nil {
            http.Redirect(w, r, "/?error=invalid_credentials", http.StatusTemporaryRedirect)
            return
        }

        token, err := generateJWT(user, []byte("secretKey"))
        if err != nil {
            http.Redirect(w, r, "/?error=generate_token_failed", http.StatusTemporaryRedirect)
            return
        }

        http.SetCookie(w, &http.Cookie{
            Name:  "jwt",
            Value: token,
        })

        http.Redirect(w, r, "/dashboard", http.StatusTemporaryRedirect)
    })

    http.HandleFunc("/dashboard", func(w http.ResponseWriter, r *http.Request) {
        token, err := r.Cookie("jwt")
        if err != nil {
            http.Redirect(w, r, "/?error=unauthorized", http.StatusTemporaryRedirect)
            return
        }

        user, err := validateJWT(token.Value, []byte("secretKey"))
        if err != nil {
            http.Redirect(w, r, "/?error=validate_token_failed", http.StatusTemporaryRedirect)
            return
        }

        t, err := tf.Get("dashboard")
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        t.Execute(w, struct{ User *User }{User: user})
    })

    log.Fatal(http.ListenAndServe(":3000", nil))
}

在上面的示例中,我们使用了http库而不是gofiber库,但实现原理相同。我们为网站创建了一个主页并使用JWT保护了所有需要进行身份验证的页面。我们还在authenticate路由上实现了一个用于用户身份验证的控制器。在我们验证用户身份后,我们使用generateJWT函数为该用户生成JWT Token并保存该Token用于随后的所有请求中。
最后,在dashboard中我们使用JWT Token来验证用户已登录,并在验证完成后向用户展示一个保护的用户仪表板。
这样,我们的RESTful身份认证系统就完成了搭建。

结论

本文介绍了如何使用Go语言和JWT来实现RESTful身份验证系统。我们使用gofiber库来创建API和Web App,并使用golang-jwt库来生成和验证JWT Token。本文还提供了两个示例代码,从根本上说明了如何生成JWT Token、如何验证JWT Token,并如何实现基于RESTful身份认证的Web应用程序。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Go-JWT-RESTful身份认证教程 - Python技术站

(0)
上一篇 2023年6月11日
下一篇 2023年6月11日

相关文章

  • 微信小程序路由跳转两种方式示例解析

    下面我将为你详细讲解“微信小程序路由跳转两种方式示例解析”的完整攻略。 一、前言 在微信小程序的开发中,跳转页面是非常常见的操作。本文将介绍微信小程序路由跳转的两种方式,分别是 wx.navigateTo 和 wx.redirectTo。 二、 wx.navigateTo wx.navigateTo 是保留当前页面,跳转到应用内的某个页面。该跳转方式支持返回…

    JavaScript 2023年6月11日
    00
  • JavaScript控制浏览器全屏显示简单示例

    关于“JavaScript控制浏览器全屏显示简单示例”的攻略,可以按照以下步骤进行: 1. HTML页面中添加按钮 首先,在HTML页面中添加一个按钮,以便在单击该按钮时全屏显示页面。可以使用以下代码: <button onclick="toggleFullScreen()">全屏显示</button> 其中onc…

    JavaScript 2023年6月11日
    00
  • 微信小程序 如何保持登录状态

    关于如何保持微信小程序登录状态,一般有两种方法: 1. 使用微信原生的登录态 我们可以调用登录 API 获取微信官方提供的登录态码(即 login code),然后将该码发送给自己的服务器进行验证和登录。服务器完成登录后,会返回一个 session key,该 key 应该在每次请求需要登录态的接口时携带,并在客户端进行本地存储,以便下次使用。 具体实现流程…

    JavaScript 2023年6月11日
    00
  • Javascript学习笔记3 作用域

    Javascript学习笔记3 作用域 在Javascript中,作用域是指变量能够被访问到的范围。掌握作用域是编写高质量代码的关键。本文将讲解Javascript中的作用域,帮助读者更好地理解Javascript的变量作用范围。 全局作用域 在Javascript中,没有在任何函数内部定义的变量都属于全局作用域,它们可以在代码中的任何地方被访问到。 var…

    JavaScript 2023年6月10日
    00
  • js字符串分割处理的几种方法(6种)

    根据您提供的话题需要,下面是对 js 字符串分割处理的几种方法进行详细的讲解和实例说明。 一、使用 split() 方法 split() 方法是 JavaScript 中常用的字符串分割方法之一。它可将一个字符串拆分成多个子字符串,然后将这些子字符串存放到一个数组中,最后返回该数组。具体使用方式如下: const str = ‘hello world’; c…

    JavaScript 2023年5月28日
    00
  • js实现的日期操作类DateTime函数代码

    JS实现的日期操作类DateTime函数代码 什么是DateTime函数 DateTime函数是一种JS函数,用于实现日期的操作,包括日期增减、格式转换等操作。 DateTime函数的实现 以下代码实现了DateTime函数,具体实现了以下功能: 获取当前日期; 日期增减; 时间格式转换。 class DateTime { constructor(date)…

    JavaScript 2023年5月27日
    00
  • angularJs中datatable实现代码

    下面给出AngularJS中datatable实现代码的完整攻略,这里使用的是AngularJS版本为1.x,实现过程中需要使用一些第三方库来支持。攻略分成以下几个步骤: 步骤一 安装必需的依赖 在开始之前,你需要在本地安装以下库: jQuery:用于操作DOM和事件处理 Bootstrap:用于样式 AngularJS:主要的MVC框架 <!– j…

    JavaScript 2023年6月11日
    00
  • 深入了解Javascript的事件循环机制

    深入了解JavaScript的事件循环机制 JavaScript 是一门单线程语言,这意味着在 JavaScript 中,代码是按顺序执行的,只有前一个任务执行完成后,才会执行下一个任务。但是 JavaScript 中有许多异步操作,如定时器、事件监听器、网络请求等,这些操作不会阻塞代码的执行,可以同时执行。那么在 JavaScript 中是如何处理异步操作…

    JavaScript 2023年5月28日
    00
合作推广
合作推广
分享本页
返回顶部