Как маршал / Unmarshal Golang OAuth2.0 токен с пользовательскими свойствами - PullRequest
0 голосов
/ 01 мая 2020

У меня есть токен OAuth 2.0 с пользовательскими свойствами, которые я хочу маршалировать и демаршировать между JSON и golang.org/x/oauth2.Token struct:

https://godoc.org/golang.org/x/oauth2#Token

Я могу загрузить пользовательские свойства в Token, используя WithExtra(), но не могу перенести маркер обратно в JSON представление со всеми пользовательскими свойствами.

Вот что я пробовал.

Используя пример токена OAuth 2.0 с пользовательскими свойствами от Apigee :

{
  "issued_at" : "1372170159093",
  "application_name" : "ccd1803b-b557-4520-bd62-ddd3abf8e501",
  "scope" : "READ",
  "status" : "approved",
  "api_product_list" : "[Product1,Product2]",
  "api_product_list_json" : ["Product1", "Product2"],
  "expires_in" : "3599", //--in seconds
  "developer.email" : "joe@weathersample.com",
  "organization_id" : "0",
  "refresh_token" : "82XMXgDyHTpFyXOaApj8C2AGIPnN2IZe",
  "client_id" : "deAVedE0W9Z9U35PAMaAJYphBJCGdrND",
  "access_token" : "shTUmeI1geSKin0TODcGLXBNe9vp",
  "organization_name" : "apifactory",
  "refresh_count" : "0"
}

Мне нужно было бы загрузить данные дважды в структуру Token, один раз, с a json.Unmarshal и секундная загрузка map[string]interface{} с использованием WithExtra().

  • Использование только WithExtra не приведет к загрузке стандартных свойств
  • Использование только json.Unmarshal(data, token) не загружает пользовательские свойства

Примечание: код может быть спарен с одним json.Unmarshal, но я оставил оба, потому что его легче читать.

Вот код:

package main

import(
    "encoding/json"
    "fmt"
    "log"

    "golang.org/x/oauth2"
)

const rawToken = `{
    "issued_at" : "1372170159093",
    "application_name" : "ccd1803b-b557-4520-bd62-ddd3abf8e501",
    "scope" : "READ",
    "status" : "approved",
    "api_product_list" : "[Product1,Product2]",
    "api_product_list_json" : ["Product1", "Product2"],
    "expires_in" : "3599",
    "developer.email" : "joe@weathersample.com",
    "organization_id" : "0",
    "refresh_token" : "82XMXgDyHTpFyXOaApj8C2AGIPnN2IZe",
    "client_id" : "deAVedE0W9Z9U35PAMaAJYphBJCGdrND",
    "access_token" : "shTUmeI1geSKin0TODcGLXBNe9vp",
    "organization_name" : "apifactory",
    "refresh_count" : "0"
}`

func ParseToken(rawToken []byte) (*oauth2.Token, error) {
    tok := &oauth2.Token{}
    err := json.Unmarshal(rawToken, tok)
    if err != nil {
        return tok, err
    }
    msi := map[string]interface{}{}
    err = json.Unmarshal(rawToken, &msi)
    if err != nil {
        return tok, err
    }
    return tok.WithExtra(msi), nil
}

func main() {
    tok, err := ParseToken([]byte(rawToken))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("application_name [%s]", tok.Extra("application_name").(string))
}

При таком подходе, если я перенаправлю маркер на JSON, я получу только access_token, refresh_token a nd expiry свойства. Стандартные свойства OAuth 2.0 , такие как scope и пользовательские свойства не включены.

Я предпочитаю, чтобы это было сделано со структурой oauth2.Token, чтобы токен мог быть создан с помощью oauth.Config например, с использованием функции oauth2.Config.Exchange(). В противном случае может потребоваться новый пакет OAuth 2.0. Некоторые библиотеки, которые я могу использовать для обработки пользовательских данных, включают github.com/dgrijalva/jwt-go для JWT и github.com/getkin/kin-openapi для спецификаций OpenAPI.

Вопросы:

  1. Есть ли более простой способ маршалировать JSON токен в oauth2.Token?
  2. Как только пользовательские свойства загружены в oauth2.Token, есть ли способ вернуть его обратно в JSON с помощью пользовательские свойства?
  3. Я сейчас использую golang.org/x/oauth2, но есть ли еще одна библиотека OAuth 2, которая имеет больше возможностей для обработки пользовательских свойств?

1 Ответ

0 голосов
/ 01 мая 2020

Возможен ли такой вариант в вашем случае?

package main

import (
    "encoding/json"
    "fmt"
    "golang.org/x/oauth2"
    "log"
)

type ExtendedToken struct {
    oauth2.Token
    IssuedAt           string   `json:"issued_at,omitempty"`
    ApplicationName    string   `json:"application_name,omitempty"`
    Scope              string   `json:"scope,omitempty"`
    Status             string   `json:"status,omitempty"`
    ApiProductList     string   `json:"api_product_list,omitempty"`
    ApiProductListJson []string `json:"api_product_list_json,omitempty"`
    ExpiresIn          string   `json:"expires_in,omitempty"`
    DeveloperEmail     string   `json:"developer.email,omitempty"`
    OrganizationId     string   `json:"organization_id,omitempty"`
    ClientId           string   `json:"client_id,omitempty"`
    OrganizationName   string   `json:"organization_name,omitempty"`
    RefreshCount       string   `json:"refresh_count,omitempty"`
}

func ParseExtendedToken(rawToken []byte) (*ExtendedToken, error) {
    tok := &ExtendedToken{}
    err := json.Unmarshal(rawToken, tok)
    if err != nil {
        return nil, err
    }
    return tok, nil
}

func main() {
    tok, err := ParseExtendedToken([]byte(rawToken))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("application_name [%s]\n", tok.ApplicationName)

    back, _ := json.Marshal(tok)
    fmt.Printf("%s\n", back)
}
...