oauth2

package module
v1.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 4, 2022 License: MIT Imports: 6 Imported by: 0

README

Golang OAuth 2.0 Server

一种开放协议,允许web、移动和桌面应用程序以简单和标准的方法进行安全授权。

Build Codecov ReportCard GoDoc License

声明

  • 这个是国外大佬的OAuth2修改版,主要是加入一些没有的功能,遵循MIT开源协议
    1. client加密(已实现)
    1. client存储在mysql,(已实现)
    1. 已申请token的client,将直接返回申请的token,而不是再去申请(已实现)
    1. 持久化login的数据(需自己实现)
  • ps:还缺少,登陆时图形验证码(需自己实现)
  • 改的不是很好,可以作为参考

Protocol Flow

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

Quick Start

Download and install
go get github.com/Jasun0925/go-oauth2-mysql
Create file server.go
package main

func main() {
	manager := manage.NewDefaultManager()
	// 设置,默认的认证code配置
	manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)
	// 设置code过期时间
	manager.SetAuthorizeCodeExp(time.Second * 10)

	// 使用jwt,或者其它
	// manager.MapAccessGenerate(generates.NewJWTAccessGenerate("", []byte("00000000"), jwt.SigningMethodHS512))
	manager.MapAccessGenerate(generates.NewAccessGenerate())

	// token使用redis存储
	redisTokenStore := oredis.NewRedisStore(&redis.Options{
		Addr:     "xxx:6379",
		Password: "xxx",
		DB:       0,
	})
	manager.MapTokenStorage(redisTokenStore)

	// client使用mysql存储,初始化clientStore的Mysql存储对象
	dbs, err := sql.Open("mysql", "xxx:xxx@tcp(xxx:3306)/xxx?charset=utf8&parseTime=true")
	if err != nil {
		log.Fatal("mysql连接失败")
	}
	clientMySqlStore := store.NewClientMySqlStore(dbs, "custom_table_name")
	// 新的改动。只实现ClientStore的GetById接口,MapClientBcryptSecretStorage是新增的,第二个参数代表使用了bcrypt加密client_Secret
	manager.MapClientBcryptSecretStorage(clientMySqlStore, true)

	// 默认的server配置,和添加管理器
	srv := server.NewServer(server.NewConfig(), manager)
	
	// 设置用户名和密码的处理,这里可以使用MySql,取出username和password
	srv.SetPasswordAuthorizationHandler(func(username, password string) (userID string, err error) {
		if username == "test" && password == "test" {
			userID = "test"
		}
		return
	})

	// 设置允许获取访问请求
	srv.SetAllowGetAccessRequest(true)
	// 设置客户端信息处理
	srv.SetClientInfoHandler(server.ClientFormHandler)

	// 错误的处理
	srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
		log.Println("Internal Error:", err.Error())
		return
	})
	srv.SetResponseErrorHandler(func(re *errors.Response) {
		log.Println("Response Error:", re.Error.Error())
	})

	// 授权处理HandleAuthorizeRequest
	http.HandleFunc("/oauth/authorize", func(w http.ResponseWriter, r *http.Request) {
		err := srv.HandleAuthorizeRequest(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}
	})

	// token处理HandleTokenRequest
	http.HandleFunc("/oauth/token", func(w http.ResponseWriter, r *http.Request) {
		srv.HandleTokenRequest(w, r)
	})
	
	// 开启服务
	log.Fatal(http.ListenAndServe(":9096", nil))
}

Build and run
go build server.go

./server
Open in your web browser

http://localhost:9096/token?grant_type=client_credentials&client_id=000000&client_secret=999999&scope=read

{
  "access_token": "J86XVRYSNFCFI233KXDL0Q",
  "expires_in": 7200,
  "scope": "read",
  "token_type": "Bearer"
}

Features

  • Easy to use
  • Based on the RFC 6749 implementation
  • Token storage support TTL
  • Support custom expiration time of the access token
  • Support custom extension field
  • Support custom scope
  • Support jwt to generate access tokens

Example

A complete example of simulation authorization code model

Simulation examples of authorization code model, please check example

Use jwt to generate access tokens

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

// ...
manager.MapAccessGenerate(generates.NewJWTAccessGenerate("", []byte("00000000"), jwt.SigningMethodHS512))

// Parse and verify jwt access token
token, err := jwt.ParseWithClaims(access, &generates.JWTAccessClaims{}, func(t *jwt.Token) (interface{}, error) {
	if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
		return nil, fmt.Errorf("parse error")
	}
	return []byte("00000000"), nil
})
if err != nil {
	// panic(err)
}

claims, ok := token.Claims.(*generates.JWTAccessClaims)
if !ok || !token.Valid {
	// panic("invalid token")
}

Store Implements

Handy Utilities

MIT License

Copyright (c) 2021 Lyric

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AccessGenerate

type AccessGenerate interface {
	Token(ctx context.Context, data *GenerateBasic, isGenRefresh bool) (access, refresh string, err error)
}

AccessGenerate 生成token的接口,带刷新

type AuthorizeGenerate

type AuthorizeGenerate interface {
	Token(ctx context.Context, data *GenerateBasic) (code string, err error)
}

AuthorizeGenerate 不带刷新

type ClientInfo

type ClientInfo interface {
	GetID() string
	GetSecret() string
	GetDomain() string
	GetUserID() string
}

ClientInfo the client information model interface

type ClientPasswordVerifier

type ClientPasswordVerifier interface {
	VerifyPassword(string) bool
}

ClientPasswordVerifier the password handler interface

type ClientStore

type ClientStore interface {
	// according to the ID for the client information
	GetByID(ctx context.Context, id string) (ClientInfo, error)
}

ClientStore the client information storage interface

type CodeChallengeMethod

type CodeChallengeMethod string

CodeChallengeMethod PCKE method

const (
	// CodeChallengePlain PCKE Method
	CodeChallengePlain CodeChallengeMethod = "plain"
	// CodeChallengeS256 PCKE Method
	CodeChallengeS256 CodeChallengeMethod = "S256"
)

func (CodeChallengeMethod) String

func (ccm CodeChallengeMethod) String() string

func (CodeChallengeMethod) Validate

func (ccm CodeChallengeMethod) Validate(cc, ver string) bool

Validate code challenge

type GenerateBasic

type GenerateBasic struct {
	Client    ClientInfo
	UserID    string
	CreateAt  time.Time
	TokenInfo TokenInfo
	Request   *http.Request
}

GenerateBasic 提供生成的令牌数据的基础

type GrantType

type GrantType string

GrantType authorization model

const (
	AuthorizationCode   GrantType = "authorization_code"
	PasswordCredentials GrantType = "password"
	ClientCredentials   GrantType = "client_credentials"
	Refreshing          GrantType = "refresh_token"
	Implicit            GrantType = "__implicit"
)

define authorization model

func (GrantType) String

func (gt GrantType) String() string

type Manager

type Manager interface {
	// get the client information
	GetClient(ctx context.Context, clientID string) (cli ClientInfo, err error)

	// generate the authorization token(code)
	GenerateAuthToken(ctx context.Context, rt ResponseType, tgr *TokenGenerateRequest) (authToken TokenInfo, err error)

	// generate the access token
	GenerateAccessToken(ctx context.Context, rt GrantType, tgr *TokenGenerateRequest) (accessToken TokenInfo, err error)

	// refreshing an access token
	RefreshAccessToken(ctx context.Context, tgr *TokenGenerateRequest) (accessToken TokenInfo, err error)

	// use the access token to delete the token information
	RemoveAccessToken(ctx context.Context, access string) (err error)

	// use the refresh token to delete the token information
	RemoveRefreshToken(ctx context.Context, refresh string) (err error)

	// according to the access token for corresponding token information
	LoadAccessToken(ctx context.Context, access string) (ti TokenInfo, err error)

	// according to the refresh token for corresponding token information
	LoadRefreshToken(ctx context.Context, refresh string) (ti TokenInfo, err error)
}

Manager authorization management interface

type ResponseType

type ResponseType string

ResponseType the type of authorization request

const (
	Code  ResponseType = "code"
	Token ResponseType = "token"
)

define the type of authorization request

func (ResponseType) String

func (rt ResponseType) String() string

type TokenGenerateRequest

type TokenGenerateRequest struct {
	ClientID            string
	ClientSecret        string
	UserID              string
	RedirectURI         string
	Scope               string
	Code                string
	CodeChallenge       string
	CodeChallengeMethod CodeChallengeMethod
	Refresh             string
	CodeVerifier        string
	AccessTokenExp      time.Duration
	Request             *http.Request
}

TokenGenerateRequest provide to generate the token request parameters

type TokenInfo

type TokenInfo interface {
	New() TokenInfo

	GetClientID() string
	SetClientID(string)
	GetUserID() string
	SetUserID(string)
	GetRedirectURI() string
	SetRedirectURI(string)
	GetScope() string
	SetScope(string)

	GetCode() string
	SetCode(string)
	GetCodeCreateAt() time.Time
	SetCodeCreateAt(time.Time)
	GetCodeExpiresIn() time.Duration
	SetCodeExpiresIn(time.Duration)
	GetCodeChallenge() string
	SetCodeChallenge(string)
	GetCodeChallengeMethod() CodeChallengeMethod
	SetCodeChallengeMethod(CodeChallengeMethod)

	GetAccess() string
	SetAccess(string)
	GetAccessCreateAt() time.Time
	SetAccessCreateAt(time.Time)
	GetAccessExpiresIn() time.Duration
	SetAccessExpiresIn(time.Duration)

	GetRefresh() string
	SetRefresh(string)
	GetRefreshCreateAt() time.Time
	SetRefreshCreateAt(time.Time)
	GetRefreshExpiresIn() time.Duration
	SetRefreshExpiresIn(time.Duration)
}

TokenInfo the token information model interface

type TokenStore

type TokenStore interface {
	// create and store the new token information
	Create(ctx context.Context, info TokenInfo) error

	// delete the authorization code
	RemoveByCode(ctx context.Context, code string) error

	// use the access token to delete the token information
	RemoveByAccess(ctx context.Context, access string) error

	// use the refresh token to delete the token information
	RemoveByRefresh(ctx context.Context, refresh string) error

	// use the authorization code for token information data
	GetByCode(ctx context.Context, code string) (TokenInfo, error)

	// use the access token for token information data
	GetByAccess(ctx context.Context, access string) (TokenInfo, error)

	// use the refresh token for token information data
	GetByRefresh(ctx context.Context, refresh string) (TokenInfo, error)

	// 获取userId的token,定义接口,实现内容
	GetTokenByUserId(ctx context.Context, userId string) string
}

TokenStore the token information storage interface

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL