golang基于JWT的多后端认证登录微服务插件loginsrv的使用

Golang基于JWT的多后端认证登录微服务插件loginsrv的使用

loginsrv是一个独立的简约登录服务器,为多个登录后端提供JWT登录功能。

功能概述

loginsrv提供最小化的认证端点,登录通过提供者执行并返回JSON Web Token(JWT)。它可以作为:

  • 独立微服务
  • Docker容器
  • Golang库
  • Caddy插件

支持的提供者后端

支持以下提供者(登录后端):

  • Htpasswd
  • OSIAM
  • Simple (通过配置的用户/密码对)
  • Httpupstream
  • OAuth2
    • GitHub登录
    • Google登录
    • Bitbucket登录
    • Facebook登录
    • Gitlab登录

配置和启动

配置选项

所有配置选项也可以通过环境变量设置,格式为LOGINSRV_OPTION_NAME。例如jwt-secret可以通过环境变量LOGINSRV_JWT_SECRET设置。

启动示例

使用loginsrv最简单的方式是通过提供的docker容器。例如使用simple提供者配置:

$ docker run -d -p 8080:8080 tarent/loginsrv -cookie-secure=false -jwt-secret my_secret -simple bob=secret

$ curl --data "username=bob&password=secret" 127.0.0.1:8080/login
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJib2IifQ.uWoJkSXTLA_RvfLKe12pb4CyxQNxe5_Ovw-N5wfQwkzXz2enbhA9JZf8MmTp9n-TTDcWdY3Fd1SA72_M20G9lQ

同样的配置也可以使用环境变量:

$ docker run -d -p 8080:8080 -E COOKIE_SECURE=false -e LOGINSRV_JWT_SECRET=my_secret -e LOGINSRV_BACKEND=provider=simple,bob=secret tarent/loginsrv

API

GET /login

默认情况下,对于未认证请求返回简单的bootstrap风格登录表单,对于已认证请求返回用户信息页面。当调用接受JSON输出时,已认证请求返回token的JSON内容。

POST /login

执行登录并返回JWT。根据内容类型和参数,可以执行经典的JSON-Rest或重定向。

DELETE /login

删除JWT cookie。在web应用中也可以通过GET|POST /login?logout=true调用。

JWT Token

根据提供者不同,token可能如下所示:

{
  "sub": "smancke",
  "picture": "https://avatars2.githubusercontent.com/u/4291379?v=3",
  "name": "Sebastian Mancke",
  "email": "s.mancke@tarent.de",
  "origin": "github"
}

提供者后端

Htpasswd

针对htpasswd文件进行认证。支持MD5、SHA1和Bcrypt,但出于安全原因建议只使用Bcrypt。

示例:

loginsrv -htpasswd file=users

Simple

Simple是一个仅用于测试的演示提供者,它在内存中保存用户/密码表。

示例:

loginsrv -simple bob=secret

OAuth2

支持OAuth Web Flow(又称3-legged-OAuth flow)。当前支持以下OAuth提供者:

  • GitHub
  • Google
  • Bitbucket
  • Facebook
  • Gitlab

OAuth提供者支持以下参数:

  • client_id - OAuth Client ID
  • client_secret - OAuth Client Secret
  • scope - 空格分隔的范围列表(可选)
  • redirect_uri - 替代重定向URI(可选)

GitHub启动示例:

$ docker run -p 80:80 tarent/loginsrv -github client_id=xxx,client_secret=yyy

自定义模板

可以通过template参数提供自定义模板。模板使用Golang模板包。

最小化的无样式登录模板如下:

<!DOCTYPE html>
<html>
  <head>
      <!-- your styles -->
  <head>
  <body>
      <!-- your header -->

      {{ if .Error}}
        <div class="alert alert-danger" role="alert">
          <strong>Internal Error. </strong> Please try again later.
        </div>
      {{end}}

      {{if .Authenticated}}

         {{template "userInfo" . }}

      {{else}}

        {{template "login" . }}

      {{end}}

      <!-- your footer -->
  </body>
</html>

自定义声明

可以通过提供包含用户数据的文件或提供声明的端点来自定义JWT令牌的内容。

用户文件

用户文件是一个YAML文件,包含将编码到令牌中的附加信息。成功通过后端系统认证后,将在文件中搜索用户,并使用claims参数的内容增强用户JWT声明参数。

示例:

- sub: bob
  origin: htpasswd
  claims:
    role: superAdmin

- email: admin@example.org
  origin: Google
  claims:
    role: admin
    projects:
      - example

- domain: example.org
  origin: Google
  claims:
    role: user
    projects:
      - example

- groups:
    - example/subgroup
    - othergroup
  origin: gitlab
  claims:
    role: admin

- claims:
    role: unknown

用户端点

用户端点是一个http端点,提供已认证用户的附加信息。成功通过后端系统认证后,将调用端点并使用提供的信息增强用户JWT声明参数。

交互示例如下:

GET /claims?origin=google&sub=test@example.com&email=test@example.com HTTP/1.1
Host: localhost:8080
Accept: */*
Authorization: Bearer token

HTTP/1.1 200 OK
Content-Type: application/json

{
  "sub":"test@example.com",
  "uid":"113",
  "origin":"google",
  "permissions": ["read", "write"]
}

更多关于golang基于JWT的多后端认证登录微服务插件loginsrv的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于JWT的多后端认证登录微服务插件loginsrv的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang基于JWT的多后端认证登录微服务插件loginsrv使用指南

loginsrv是一个轻量级的登录微服务,支持多种后端认证方式并生成JWT令牌。下面我将详细介绍其使用方法和Golang示例代码。

1. loginsrv简介

loginsrv主要特性:

  • 支持多种后端认证方式:htpasswd、OSIAM、HTTP基本认证、LDAP、OAuth2等
  • 生成JWT令牌
  • 轻量级,易于集成
  • 支持CORS
  • 可配置的JWT过期时间

2. 安装loginsrv

go get github.com/tarent/loginsrv

3. 基本使用示例

3.1 简单启动

loginsrv --jwt-secret mysecret --text-login

3.2 使用htpasswd后端

loginsrv --jwt-secret mysecret --htpasswd /path/to/users.htpasswd

4. Golang集成示例

4.1 直接调用loginsrv

package main

import (
	"log"
	"os"
	"os/exec"
)

func main() {
	cmd := exec.Command("loginsrv",
		"--jwt-secret", "mysecretkey",
		"--backend", "provider=simple",
		"--backend", "provider=htpasswd,file=users.htpasswd",
		"--cookie-domain", "example.com",
		"--cookie-name", "jwt_token",
		"--host", "0.0.0.0",
		"--port", "8080",
	)
	
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
	
	log.Println("Login service started on port 8080")
	
	if err := cmd.Wait(); err != nil {
		log.Fatal(err)
	}
}

4.2 作为中间件使用

package main

import (
	"net/http"
	"os"
	
	"github.com/tarent/loginsrv/login"
)

func main() {
	config := login.DefaultConfig()
	config.JwtSecret = "mysecretkey"
	config.Backends = login.BackendOptions{
		"simple": map[string]string{},
		"htpasswd": map[string]string{
			"file": "users.htpasswd",
		},
	}
	config.Cookie.Domain = "example.com"
	config.Cookie.Name = "jwt_token"
	
	handler, err := login.NewHandler(config)
	if err != nil {
		panic(err)
	}
	
	http.Handle("/login", handler)
	
	// 保护的路由示例
	protected := http.NewServeMux()
	protected.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Protected API"))
	})
	
	http.Handle("/api/", handler.Middleware(protected))
	
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	
	http.ListenAndServe(":"+port, nil)
}

5. JWT验证示例

package main

import (
	"fmt"
	"net/http"
	"time"
	
	"github.com/dgrijalva/jwt-go"
)

func verifyJWT(jwtToken, secret string) (bool, error) {
	token, err := jwt.Parse(jwtToken, 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 []byte(secret), nil
	})
	
	if err != nil {
		return false, err
	}
	
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		fmt.Println("User:", claims["sub"])
		fmt.Println("Expires:", time.Unix(int64(claims["exp"].(float64)), 0))
		return true, nil
	}
	
	return false, nil
}

func protectedHandler(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie("jwt_token")
	if err != nil {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	
	if valid, _ := verifyJWT(cookie.Value, "mysecretkey"); valid {
		w.Write([]byte("Welcome to protected area!"))
	} else {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
	}
}

func main() {
	http.HandleFunc("/protected", protectedHandler)
	http.ListenAndServe(":8080", nil)
}

6. 多后端配置示例

loginsrv支持同时配置多个认证后端:

loginsrv \
  --jwt-secret mysecret \
  --backend provider=simple,bob=secret \
  --backend provider=htpasswd,file=users.htpasswd \
  --backend provider=ldap,host=ldap.example.com,base=dc=example,dc=com

7. 生产环境建议

  1. 使用强JWT密钥
  2. 启用HTTPS
  3. 设置合理的JWT过期时间
  4. 定期轮换JWT密钥
  5. 监控登录服务

8. 总结

loginsrv为Golang应用提供了简单易用的JWT认证解决方案,支持多种后端认证方式,可以轻松集成到现有系统中。通过中间件方式使用,可以方便地保护API路由。

以上示例展示了loginsrv的基本用法和Golang集成方式,您可以根据实际需求进行调整和扩展。

回到顶部