1. 程式人生 > >用 Identity Server 4 (JWKS 端點和 RS256 演算法) 來保護 Python web api

用 Identity Server 4 (JWKS 端點和 RS256 演算法) 來保護 Python web api

目前正在使用asp.net core 2.0 (主要是web api)做一個專案, 其中一部分功能需要使用js客戶端呼叫python的pandas, 所以需要建立一個python 的 rest api, 我暫時選用了hug, 官網在這: http://www.hug.rest/.

目前專案使用的是identity server 4, 還有一些web api和js client.

下面開始配置identity server 4, 我使用的是windows.

新增ApiResource:

在 authorization server專案中的配置檔案新增紅色部分, 這部分就是python hug 的 api:

public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource(SalesApiSettings.ApiName, SalesApiSettings.ApiDisplayName) {
                    UserClaims = { JwtClaimTypes.Name, JwtClaimTypes.PreferredUserName, JwtClaimTypes.Email }
                },
                
new ApiResource("purchaseapi", "採購和原料庫API") { UserClaims = { JwtClaimTypes.Name, JwtClaimTypes.PreferredUserName, JwtClaimTypes.Email } }, new ApiResource("hugapi", "Hug API") { UserClaims = { JwtClaimTypes.Name, JwtClaimTypes.PreferredUserName, JwtClaimTypes.Email } }
}; }

修改js Client的配置:

// Sales JavaScript Client
                new Client
                {
                    ClientId = SalesApiSettings.ClientId,
                    ClientName = SalesApiSettings.ClientName,
                    AllowedGrantTypes = GrantTypes.Implicit,
                    AllowAccessTokensViaBrowser = true,
                    AccessTokenLifetime = 60 * 10,
                    AllowOfflineAccess = true,
                    RedirectUris =           { $"{Startup.Configuration["MLH:SalesApi:ClientBase"]}/login-callback", $"{Startup.Configuration["MLH:SalesApi:ClientBase"]}/silent-renew.html" },
                    PostLogoutRedirectUris = { Startup.Configuration["MLH:SalesApi:ClientBase"] },
                    AllowedCorsOrigins =     { Startup.Configuration["MLH:SalesApi:ClientBase"] },
                    AlwaysIncludeUserClaimsInIdToken = true,
                    AllowedScopes =
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        IdentityServerConstants.StandardScopes.Email,
                        SalesApiSettings.ApiName,
                        "hugapi"
                    }
                }

修改js客戶端的oidc client配置選項:

新增 hugapi, 與authorization server配置對應.

{
        authority: 'http://localhost:5000',
        client_id: 'sales',
        redirect_uri: 'http://localhost:4200/login-callback',
        response_type: 'id_token token',
        scope: 'openid profile salesapi hugapi email',
        post_logout_redirect_uri: 'http://localhost:4200',

        silent_redirect_uri: 'http://localhost:4200/silent-renew.html',
        automaticSilentRenew: true,
        accessTokenExpiringNotificationTime: 4,
        // silentRequestTimeout:10000,
        userStore: new WebStorageStateStore({ store: window.localStorage })
    }

建立Python Hug api

(可選) 安裝virtualenv:

pip install virtualenv

然後在某個地方建立一個目錄:

mkdir hugapi && cd hugapi

建立虛擬環境:

virtualenv venv

啟用虛擬環境:

venv\Scripts\activate

然後大約這樣顯示:

安裝hug:

pip install hug

這時, 參考一下hug的文件. 然後建立一個簡單的api. 建立檔案main.py:

import hug

@hug.get('/home')
def root():
    return 'Welcome home!'

執行:

hug -f main.py

結果好用:

然後還需要安裝這些:

pip install cryptography pyjwt hug_middleware_cors

其中pyjwt是一個可以encode和decode JWT的庫, 如果使用RS256演算法的話, 還需要安裝cryptography. 

而hug_middleware_cors是hug的一個跨域訪問中介軟體(因為js客戶端和這個api不是在同一個域名下).

新增需要的引用:

import hug
import jwt
import json
import urllib.request
from jwt.algorithms import get_default_algorithms
from hug_middleware_cors import CORSMiddleware

然後正確的做法是通過Authorization Server的discovery endpoint來找到jwks_uri,

identity server 4 的discovery endpoint的地址是:

但我還是直接寫死這個jwks_uri吧:

response = urllib.request.urlopen('http://localhost:5000/.well-known/openid-configuration/jwks')
still_json = json.dumps(json.loads(response.read())['keys'][0])

identity server 4的jwks_uri, 裡面是public key, 它的結構是這樣的:

而我使用jwt庫, 的引數只能傳入一個證書的json, 也可就是keys[0].

所以上面的最後一行程式碼顯得有點.......

如果使用python-jose這個庫會更簡單一些, 但是在我windows電腦上總是安裝失敗, 所以還是湊合用pyjwt吧.

然後讓hug api使用cors中介軟體:

api = hug.API(__name__)
api.http.add_middleware(CORSMiddleware(api))

然後是hug的authentication部分:

def token_verify(token):
    token = token.replace('Bearer ', '')
    rsa = get_default_algorithms()['RS256']
    cert = rsa.from_jwk(still_json)
    try:
        result = jwt.decode(token, cert, algorithms=['RS256'], audience='hugapi')
        print(result)
        return result
    except jwt.DecodeError:
        return False

token_key_authentication = hug.authentication.token(token_verify)

通過rsa.from_jwk(json) 就會得到key (certificate), 然後通過jwt.decode方法可以把token進行驗證並decode, 演算法是RS256, 這個方法要求如果token裡面包含了aud, 那麼方法就需要要指定audience, 也就是hugapi.

最後修改api 方法, 加上驗證:

@hug.get('/home', requires=token_key_authentication)
def root():
    return 'Welcome home!'

最後執行 hug api:

hug -f main.py

埠應該是8000.

執行js客戶端,登陸, 並呼叫這個hug api http://localhost:8000/home:

(我的js客戶端是angular5的, 這個沒法開源, 公司財產, 不過配置oidc-client還是很簡單的, 使用)

返回200, 內容是: 

看一下hug的log:

token被正確驗證並解析了. 所以可以進入root方法了.

 
其他的python api框架, 都是同樣的道理.

今日修改後的程式碼: 

import json
import hug
import jwt
import requests
from jwt.algorithms import get_default_algorithms
from hug_middleware_cors import CORSMiddleware

api = hug.API(__name__)
api.http.add_middleware(CORSMiddleware(api))


def token_verify(token):
    access_token = token.replace('Bearer ', '')
    token_header = jwt.get_unverified_header(access_token)
    res = requests.get(
        'http://localhost:5000/.well-known/openid-configuration')
    jwk_uri = res.json()['jwks_uri']
    res = requests.get(jwk_uri)
    jwk_keys = res.json()

    rsa = get_default_algorithms()['RS256']
    key = json.dumps(jwk_keys['keys'][0])
    public_key = rsa.from_jwk(key)

    try:
        result = jwt.decode(access_token, public_key, algorithms=[
                            token_header['alg']], audience='api1')
        return result
    except jwt.DecodeError:
        return False


token_key_authentication = hug.authentication.token(token_verify)


@hug.get('/identity', requires=token_key_authentication)
def root(user: hug.directives.user):
    print(user)
    return user

 我的部落格即將搬運同步至騰訊雲+社群,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan

相關推薦

Identity Server 4 (JWKS 端點 RS256 演算法) 保護 Python web api

目前正在使用asp.net core 2.0 (主要是web api)做一個專案, 其中一部分功能需要使用js客戶端呼叫python的pandas, 所以需要建立一個python 的 rest api, 我暫時選用了hug, 官網在這: http://www.hug.rest/. 目前專案使用的是ide

Identity Server 4 -- OAuth 2.0 超級簡介

分隔 理解 大小 很多 應用程序 identity 復制 字符串 返回 OAuth 2.0 簡介 OAuth有一些定義: OAuth 2.0是一個委托協議, 它可以讓那些控制資源的人允許某個應用以代表他們來訪問他們控制的資源, 註意是代表這些人, 而不是假冒或模仿這些人

第47章 授權端點(Authorize Endpoint) - Identity Server 4 中文文檔(v1.0.0)

Nid str ons 響應 challenge redirect 授權 轉發 必須 授權端點可用於通過瀏覽器請求令牌或授權碼。此過程通常涉及最終用戶的身份驗證和可選的同意。 註意 IdentityServer支持OpenID Connect和OAuth 2.0授權請求參

第46章 發現端點(Discovery Endpoint) - Identity Server 4 中文文檔(v1.0.0)

-c 回發 point ecs mode identity 可用 元數據 註意 發現端點可用於檢索有關IdentityServer的元數據 - 它返回發布者名稱,密鑰材料,支持的範圍等信息。有關詳細信息,請參閱規範。 發現端點可通過/.well-known/openid-c

學習Identity Server 4的預備知識

發布 開發 簡單的 密碼 是否 alt imp load 通信 我要使用asp.net core 2.0 web api 搭建一個基礎框架並立即應用於一個實際的項目中去. 這裏需要使用identity server 4 做單點登陸. 下面就簡單學習一下相關的預備知識. 基於

使用Identity Server 4建立Authorization Server (2)

可能 參數 ecif fig register startup 類型 cal mat 第一部分: http://www.cnblogs.com/cgzl/p/7780559.html 第一部分主要是建立了一個簡單的Identity Server. 接下來繼續: 建立Web

使用Identity Server 4建立Authorization Server (5)

連接字符串 mapr path 框架 ise network edit setting pin 預備知識: http://www.cnblogs.com/cgzl/p/7746496.html 第一部分: http://www.cnblogs.com/cgzl/p/7780

使用Identity Server 4建立Authorization Server (6) - js(angular5) 客戶端

include 節點 ogr 包含 發的 for icon ets list 預備知識: http://www.cnblogs.com/cgzl/p/7746496.html 第一部分: http://www.cnblogs.com/cgzl/p/7780559.html

Identity Server 4 - Hybrid Flow - 保護API資源

還需 defaults rest 兩個 ade die tar try 意思 這個系列文章介紹的是Identity Server 4 的 Hybrid Flow, 前兩篇文章介紹了如何保護MVC客戶端, 本文介紹如何保護API資源. 保護MVC客戶端的文章: https:

eShopOnContainers 看微服務③:Identity Service OAuth 2.0 簡介 OpenID Connect 簡介 Identity Server 4 eShopOnContainers 知多少[3]:Identity microservice

引言 通常,服務所公開的資源和 API 必須僅限受信任的特定使用者和客戶端訪問。那進行 API 級別信任決策的第一步就是身份認證——確定使用者身份是否可靠。 在微服務場景中,身份認證通常統一處理。一般有兩種實現形式: 基於API 閘道器中心化認證:要求客戶端必須都通過閘道器訪問微服務。(這就要求

學習Identity Server 4的預備知識 (誤刪, 重補)

我要使用asp.net core 2.0 web api 搭建一個基礎框架並立即應用於一個實際的專案中去. 這裡需要使用identity server 4 做單點登陸. 下面就簡單學習一下相關的預備知識. 基於Token的安全驗證體系 這個比較簡單, 簡單來說就是為了證明我們有訪問許可權, 我們首先需

使用Identity Server 4建立Authorization Server (3)

上一部分簡單的弄了個web api 並通過Client_Credentials和ResourceOwnerPassword兩種方式獲取token然後進行api請求. 這次講一下Authentication 身份驗證 (而Authorization是授權, 注意區分), 使用的是OpenIdCon

使用Identity Server 4建立Authorization Server (1)

官方文件很詳細的. 使用OAuth可以更安全, 這裡我們的authorization server和web api 以及網站將分別獨立執行.  建立authorization server 建立asp.net core 專案使用空模板. 專案建立後, 執行方式改為使用控制檯執行而不是IISEx

Identity Server 4

Claims 我不知道怎麼樣翻譯這個詞比較好, 所以我一般就不翻譯了. 在前一篇文章裡, MVC客戶端配置身份認證的時候有這麼一句話(Startup的ConfigureServices): JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Cl

Identity Server 4 預備知識 -- OAuth 2.0 簡介

OAuth 2.0 簡介 OAuth有一些定義: OAuth 2.0是一個委託協議, 它可以讓那些控制資源的人允許某個應用以代表他們來訪問他們控制的資源, 注意是代表這些人, 而不是假冒或模仿這些人. 這個應用從資源的所有者那裡獲得到授權(Authorization)和access token, 隨後就可

Identity Server 4 預備知識 -- OpenID Connect 簡介

這篇文章我要介紹一下 OpenID Connect. OAuth 2.0 不是身份認證協議 OAuth 2.0 不是身份認證(Authentication)協議. 為什麼有人會認為OAuth 2.0具有身份認證的功能? 這是因為OAuth2經常作為身份認證(Authentication)協議的一部分來

使用Identity Server 4建立Authorization Server (4)

上一篇講了使用OpenId Connect進行Authentication. 下面講 Hybrid Flow和Offline Access 目前我們解決方案裡面有三個專案 Authorization Server, Web api和Mvc Client. 在現實世界中, 他們可能都在不同

第44章 添加新協議 - Identity Server 4 中文文檔(v1.0.0)

iges author 重用 sign tsig dds mode 上下文 bool 除了對OpenID Connect和OAuth 2.0的內置支持之外,IdentityServer4還允許添加對其他協議的支持。 您可以將這些附加協議端點添加為中間件或使用例如MVC控制器

第41章 CORS - Identity Server 4 中文文檔(v1.0.0)

應用程序 lec 裝飾 conf tst client 模式 ria logger 第41章 CORS IdentityServer中的許多端點將通過基於JavaScript的客戶端的Ajax調用進行訪問。鑒於IdentityServer最有可能托管在與這些客戶端不同的源上

第42章 發現(discovery) - Identity Server 4 中文文檔(v1.0.0)

開頭 option entity .sh 情況下 cover 我們 setting tom 可以在*https://baseaddress/.well-known/openid-configuration*找到發現文檔。它包含有關IdentityServer的端點,密鑰材料