如何用IdentityServer4来保护Pythonwebapi

这篇文章将为大家详细讲解有关如何用Identity Server 4来保护 Python web api,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

网站的建设成都创新互联公司专注网站定制,经验丰富,不做模板,主营网站定制开发.小程序定制开发,H5页面制作!给你焕然一新的设计体验!已为水泥搅拌车等企业提供专业服务。

目前正在使用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.

项目的早期后台源码: https://github.com/solenovex/asp.net-core-2.0-web-api-boilerplate

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

添加ApiResource:

在 authorization server项目中的配置文件添加红色部分, 这部分就是python hug 的 api:

public static IEnumerable GetApiResources()

        {

            return new List

            {

                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

然后大约这样显示:

如何用Identity Server 4来保护 Python web api

安装hug:

pip install hug

这时, 参考一下hug的文档. 然后建立一个简单的api. 建立文件main.py:

import hug

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

运行:

hug -f main.py

结果好用:

如何用Identity Server 4来保护 Python web api

然后还需要安装这些:

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的地址是:

http://localhost:5000/.well-known/openid-configuration, 里面能找到各种节点和信息:

如何用Identity Server 4来保护 Python web api

但我还是直接写死这个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, 它的结构是这样的:

如何用Identity Server 4来保护 Python web api

而我使用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还是很简单的, 使用)

如何用Identity Server 4来保护 Python web api

返回200, 内容是: 

如何用Identity Server 4来保护 Python web api

看一下hug的log:

如何用Identity Server 4来保护 Python web api

token被正确验证并解析了. 所以可以进入root方法了.

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

可以使用这个例子自行搭建 https://github.com/IdentityServer/IdentityServer4.Samples/tree/release/Quickstarts/7_JavaScriptClient 

关于如何用Identity Server 4来保护 Python web api就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


当前题目:如何用IdentityServer4来保护Pythonwebapi
文章分享:http://hbruida.cn/article/igpepj.html