详解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日

相关文章

  • js制作轮播图效果

    下面是详细讲解“js制作轮播图效果”的完整攻略: 1. 确定需求 首先确定需求,也就是轮播图的要求。比如需要自动播放、可以手动切换、需要圆点分页器等等。根据不同的需求,我们会采用不同的实现方法。 在这里,我们暂定轮播图的基本要求为:自动播放、手动切换、圆点分页器。 2. HTML结构 根据需求,确定好HTML结构的基本框架,比如轮播图盒子、轮播图图片、圆点分…

    JavaScript 2023年6月11日
    00
  • JavaScript实现网页计算器功能

    JavaScript是现代网页开发中不可或缺的语言,可以用来实现网页计算器功能。以下是实现网页计算器功能的完整攻略,包含两条示例说明: 1. 创建网页结构 在HTML页面中创建一个计算器界面。可以使用<div>元素来包含计算器所有内容。 在这个<div>元素中,可以创建多个<button>元素,每个<button&g…

    JavaScript 2023年6月11日
    00
  • JS 实现 ajax 异步浏览器兼容问题

    JS 实现 ajax 异步浏览器兼容问题 什么是 AJAX AJAX (Asynchronous JavaScript and XML) 是一种通过后台与服务器进行数据交换,而无需重新加载整个页面的技术,在 Web 开发中广泛应用。以下是 AJAX 的一些优点: 可以在不刷新页面的情况下更新页面内容 能够异步地获取数据,并把数据显示在页面上 能够使用服务器应…

    JavaScript 2023年6月11日
    00
  • 轻量级的原生js日历插件calendar.js使用指南

    轻量级的原生js日历插件calendar.js使用指南 什么是calendar.js? calendar.js是一款轻量级的原生JavaScript日历插件,不依赖任何第三方库,可快速集成到你的网站或应用中。 如何使用calendar.js? 步骤一:引入calendar.js文件 将calendar.js文件引入到你的网页中。 <script src…

    JavaScript 2023年5月27日
    00
  • javascript alert乱码的解决方法

    Javascript alert乱码的解决方法其实比较简单,主要就是需要提前设置网页的charset为UTF-8,接下来,我将详细说明如何进行解决,具体步骤如下: 设置charset为UTF-8 打开HTML文件或模板文件,添加以下代码到HTML文件头部,对于网站的每个页面都需要添加: <meta charset="UTF-8"&g…

    JavaScript 2023年5月19日
    00
  • ES9的新特性之正则表达式RegExp详解

    ES9的新特性之正则表达式RegExp详解 简介 正则表达式(RegExp)是JavaScript中一个十分重要的概念,主要用于字符串匹配和替换。在ES9中,新增了一些正则表达式的新特性,本文将对这些新特性作详细的解释和演示。 s 修饰符 在ES9中,正则表达式新增了一个s修饰符,它代表匹配所有字符。在普通的正则表达式中,.只能匹配除换行符之外的所有字符。但…

    JavaScript 2023年6月10日
    00
  • es6 filter() 数组过滤方法总结

    标题:ES6 filter() 数组过滤方法总结 介绍:在ES6中,filter()是一个常用的数组方法,它可以根据指定的条件来过滤数组元素。本文将详细讲解ES6中的filter()方法,包括其参数和用法,同时提供两个实际的示例来帮助读者更好地理解。 正文: 参数和用法 ES6中的filter()方法接受一个回调函数作为参数,回调函数可以接受三个参数,分别是…

    JavaScript 2023年5月27日
    00
  • PowerShell小技巧实现IE Web自动化

    PowerShell小技巧实现IE Web自动化 简介 PowerShell是一种流行的管理、自动化和任务脚本语言,可以用于Windows平台上的各种任务,包括Web自动化。本文将介绍如何使用PowerShell实现IE Web自动化,并提供两个示例以说明具体实现方法。 PowerShell与IE Web自动化 PowerShell通过IE Com对象实现W…

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