Last active
November 9, 2019 08:22
-
-
Save yukpiz/e2804f182067d5318fa94a2d6f868ffb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package application | |
import ( | |
"context" | |
"strings" | |
) | |
// ... interfaceやstructの定義は一般的なものなので省略 | |
func (app *application) Authorize(ctx context.Context, token string) (*model.Certification, error) { | |
// JWTの検証をclientに任せる | |
clms, err := app.JWTClient.ParseJWT(ctx, token) | |
// claimsからsubを取得する | |
var sub string = (*clms)["sub"].(string) | |
// JWT発行はAuth0なのでsubが空はありえないが、 | |
// 生成は可能なのでgormに空文字を渡さないようにここでブロックする | |
if len(strings.TrimSpace(sub)) == 0 { | |
return nil, domain.Errors.NotAuthorizedError | |
} | |
// subからユーザー情報を取得する | |
c, err := app.CertificationRepository.FindByClaimSub(ctx, app.Repository, sub) | |
if err != nil { | |
return nil, err | |
} | |
if c == nil { | |
return nil, domain.Errors.NotAuthorizedError | |
} | |
return c, nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package client | |
import ( | |
"context" | |
"github.com/dgrijalva/jwt-go" | |
) | |
// ... interfaceやstructの実装は一般的なものなので省略する | |
func (c *client) ParseJWT(ctx context.Context, token string) (map[string]interface{}, error) { | |
// clientの生成時に読み込んだpemファイルからRSA公開鍵を取得する | |
verifyKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(c.pem)) | |
if err != nil { | |
return nil, err | |
} | |
// JWTの検証とパースを行う | |
token, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { | |
// トークン認証用のメソッドが正しいかを確認 | |
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { | |
return nil, domain.Errors.JWTNotSupportedMethodError // unexpected signing error | |
} | |
return verifyKey, nil | |
}) | |
if err != nil { | |
// エラー時のエラー内容を確認して分岐させる | |
ve, ok := err.(*jwt.ValidationError) | |
if !ok { | |
return nil, domain.Errors.JWTValidationError // token is invalided | |
} | |
if ve.Errors&jwt.ValidationErrorExpired != 0 { | |
return nil, domain.Errors.JWTExpiredError // token is expired | |
} | |
return nil, err | |
} | |
if token == nil || !token.Valid { | |
return nil, domain.Errors.JWTInvalidError // token is invalided | |
} | |
claims, ok := token.Claims.(jwt.MapClaims) | |
if !ok { | |
return nil, domain.Errors.JWTNotFoundClaimsError // not found claims | |
} | |
return &claims, nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package middleware | |
import ( | |
"context" | |
"fmt" | |
"os" | |
"regexp" | |
"google.golang.org/grpc" | |
"google.golang.org/grpc/metadata" | |
) | |
// ... interfaceやstructの定義は一般的なものなので省略 | |
// grpc_middlewareで埋め込まれるinterceptorの実装になります | |
// middlewareはリクエストやレスポンスの構造に関与する役割を持っています | |
func (m *authMiddleware) AuthorizationUnaryServerInterceptor() grpc.UnaryServerInterceptor { | |
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, uhandler grpc.UnaryHandler) (interface{}, error) { | |
// TODO: 認証が不要なAPIなどがあれば、 | |
// ここでメソッド名でのマッチをして認証処理をスキップさせる | |
var token string | |
var err error | |
// context.Contextからmetadataを生成します | |
// gRPCヘッダーを参照できるようになります | |
md, ok := metadata.FromIncomingContext(ctx) | |
if !ok { | |
return nil, m.newErrorResponse(nil, xerrors.Errorf("Incoming context error: %v", ctx)) | |
} | |
// metadataのAuthorizationヘッダからJWTを取り出します | |
token, err = grpc_auth.AuthFromMD(ctx, MetaDataAuthPrefix) | |
if err != nil { | |
return nil, m.newErrorResponse(ctx, err) | |
} | |
// JWTの検証とユーザー情報の抽出をapplicationに任せます | |
c, err := m.AuthApplication.Authorize(ctx, token) | |
if err != nil { | |
return nil, m.newErrorResponse(ctx, err) | |
} | |
// ユーザー情報をcontextに埋め込みます | |
// このmiddlewareの後に続くAPIは、contextからユーザー情報を得ることができます | |
newCtx := context.WithValue(ctx, domain.CertificationKeyName, c) | |
return uhandler(newCtx, req) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment