本地搭建hydra服务用go以验证oidc流程

发布于:2024-05-09 ⋅ 阅读:(35) ⋅ 点赞:(0)

目录

1、docker搭建hydra,环境配置:

2、搭建完成后服务调用:

2.1保证服务正常启动:

2.2 通过postman调用,获取client_id:

2.3 通过client_id,实现oauth2/auth调用

3. 通过go语言实现oidc验证:


1、docker搭建hydra,环境配置:

环境:windows10

docker-compose.yml:

version: "3.7"
services:
  hydra:
    image: oryd/hydra:v2.0.2
    ports:
      - "4444:4444" # 公共端口
      - "4445:4445" # 管理端口
      - "5555:5555" # 用于 Hydra 令牌用户的端口
    command: serve -c /etc/config/hydra/hydra.yml all --dev
    volumes:
      - type: bind
        source: C:\workspace\hydra\config
        target: /etc/config/hydra
    environment:
      - DSN=postgres://hydra:secret@postgresd:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4
    restart: unless-stopped
    depends_on:
      - hydra-migrate
    networks:
      - intranet
  hydra-migrate:
    image: oryd/hydra:v2.0.2
    environment:
      - DSN=postgres://hydra:secret@postgresd:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4
    command: migrate -c /etc/config/hydra/hydra.yml sql -e --yes #这个是在容器中
    volumes:
      - type: bind
        source: C:\workspace\hydra\config # 公共端口挂的卷是windows上
        target: /etc/config/hydra
    restart: on-failure
    networks:
      - intranet
  consent:
    environment:
      - HYDRA_ADMIN_URL=http://hydra:4445
    image: oryd/hydra-login-consent-node:v2.0.2
    ports:
      - "3000:3000"
    restart: unless-stopped
    networks:
      - intranet
  postgresd:
    image: postgres:11.8
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=hydra
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=hydra
    networks:
      - intranet
networks:
  intranet:

配置yaml:

serve:
  cookies:
    same_site_mode: Lax

urls:
  self:
    issuer: http://127.0.0.1:4444
  consent: http://127.0.0.1:3000/consent
  login: http://127.0.0.1:3000/login
  logout: http://127.0.0.1:3000/logout

secrets:
  system:
    - youReallyNeedToChangeThis

oidc:
  subject_identifiers:
    supported_types:
      - pairwise
      - public
    pairwise:
      salt: youReallyNeedToChangeThis

2、搭建完成后服务调用:

2.1保证服务正常启动:

2.2 通过postman调用,获取client_id:

post:http://localhost:4445/admin/clients

body:

{
    "client_name": "crm",
    "token_endpoint_auth_method": "client_secret_basic",
    "redirect_uris": [
        "http://127.0.0.1:5555/callback"
    ],
    "scope": "openid offline",
    "grant_types": [
        "authorization_code",
        "refresh_token",
        "implicit",
        "client_credentials"
    ],
    "response_types": [
        "code",
        "id_token",
        "token"
    ]
}

2.3 通过client_id,实现oauth2/auth调用

3. 通过go语言实现oidc验证:

只是写了个思路,流程没有走通,只供参考,有厉害的大神可以完善补充一下,下面的代码只是提供了思路,搭建完上面的环境后,可以用以自己玩耍,有兴趣的流程自己走通完善:

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/coreos/go-oidc"
	"golang.org/x/oauth2"
)

func main() {
	ctx := context.Background()

	// 创建 OIDC 配置
	provider, err := oidc.NewProvider(ctx, "http://127.0.0.1:4444")
	if err != nil {
		log.Fatalf("Failed to create OIDC provider: %v", err)
	}

	// 创建 OAuth2 配置
	oauth2Config := oauth2.Config{
		ClientID:     "af7da551-1ddd-4e6e-9b52-62d7535e57f2",       // 你的 OAuth2 客户端 ID
		ClientSecret: os.Getenv("CLIENT_SECRET"),   // 你的 OAuth2 客户端密钥
		RedirectURL:  "http://127.0.0.1:5555/callback", // 你的回调 URL
		Endpoint:     provider.Endpoint(),
		Scopes:       []string{oidc.ScopeOpenID, "profile", "email"},
	}

	// 创建 OIDC 验证器
	verifier := provider.Verifier(&oidc.Config{ClientID: oauth2Config.ClientID})

	log.Printf("Received verifier: %s", verifier)

	// 设置回调处理函数
	http.HandleFunc("/oauth2/auth", func(w http.ResponseWriter, r *http.Request) {
		// 获取 OAuth2 令牌
		log.Printf("Received url: %s", r.URL.Query())
		code := r.URL.Query().Get("code")
		log.Printf("Received code: %s", code)
		if code == "" {
			http.Error(w, "Missing code parameter", http.StatusBadRequest)
			return
		}
		log.Printf("Received code: %s", code)

		oauth2Token, err := oauth2Config.Exchange(ctx, code)
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed to exchange token: %v", err), http.StatusInternalServerError)
			return
		}

		// 使用令牌获取用户信息
		idToken, ok := oauth2Token.Extra("id_token").(string)
		if !ok {
			http.Error(w, "No id_token", http.StatusInternalServerError)
			return
		}

		// 验证 ID 令牌
		_, err = verifier.Verify(ctx, idToken)
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed to verify token: %v", err), http.StatusUnauthorized)
			return
		}

		// 验证通过,输出用户信息
		fmt.Fprintf(w, "Authentication successful! User: %v", oauth2Token)
	})

	// 启动服务器
	log.Fatal(http.ListenAndServe(":8080", nil))
}