观测云集成 Lark SSO 最佳实践

    banner.jpg

    介绍

    Lark官方整体对接流程

    Lark 流程获取说明

    获取 code

    接口文档:获取登录授权码code

    获取 user_access_token

    接口文档:获取 user_access_token

    获取用户身份信息

    接口文档:获取用户身份信息

    刷新 user_access_token

    接口文档:刷新 user_access_token

    准备

    验证环境准备

    • 部署版本观测云

    官方文档:https://docs.guance.com/deployment/

    • 安装 Dataflux Func 平台

    官方文档:https://func.guance.com/doc/maintenance-guide-helm/

    • 观测云 OIDC 集成对接官方指引

    官方文档:https://docs.guance.com/deployment/oidc-custom-url/

    Lark 开放平台配置

    Lark 应用配置需要访问开发后台新增应用管理配置

    Lark - 测试应用信息

    Name AppID AppSecret
    Guance_ cli_xxxxxxxxxx IDxxxxxxxx

    Lark - 安全访问配置

    • (必须)需要根据添加 redirect_uri 的回调地址
    Url 说明
    http://{{ 观测云主访问域名 }}/oidc/callback redirect_uri地址

    • (按需)IP白名单设置

    Lark - 应用权限配置

    SSO 身份验证需要对应用开放用户信息的相关权限

    权限名 说明 是否必选
    contact:user.employee:readonly 用户受雇信息 按需
    contact:user.email:readonly 用户邮箱信息 必选
    contact:user.employee_id:readonly 用户user ID 信息 必选
    contact:user.phone:readonly 用户手机号信息 按需

    观测云平台配置

    打开 部署版本「launcher」 访问页面,点击「设置」 -- 「修改应用配置」。

    在 「 forethought-webclient」命名空间 的「frontNginx」中,追加访问路由。

            location /oidc/login {
                proxy_connect_timeout 5;
                proxy_send_timeout 5;
                proxy_read_timeout 300;
                proxy_http_version 1.1;
                proxy_set_header Connection "keep-alive";
                add_header Access-Control-Allow-Origin *;
                add_header Access-Control-Allow-Headers X-Requested-With;
                add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
                proxy_pass http://inner.forethought-core:5000/api/v1/inner/oidc/login;
            }
    
            location /oidc/callback {
                proxy_connect_timeout 5;
                proxy_send_timeout 5;
                proxy_read_timeout 300;
                proxy_http_version 1.1;
                proxy_set_header Connection "keep-alive";
                add_header Access-Control-Allow-Origin *;
                add_header Access-Control-Allow-Headers X-Requested-With;
                add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
                proxy_pass http://inner.forethought-core:5000/api/v1/inner/oidc/callback;
           }
    

    在 「forethought-core」 命名空间中 「core」添加 OIDC 配置。

     OIDCClientSet:
      # OIDC Endpoints 配置地址,即完整的 `https://xxx.xxx.com/xx/.well-known/openid-configuration` 地址.
      wellKnowURL: "http://func-server.func:8088/api/v1/sync/auln-well-know"
      # 由认证服务提供的 客户端ID
      clientId: cli_xxxxxxxx. # 修改为您的应用 clientId
      # 客户端的 Secret key
      clientSecret: IDGgZxxxxxxxxxd  # 修改为您的应用 clientSecret
      scope: ""
      mapping:
        # 认证服务中,登录账号的用户名,必填,如果值不存在,则取 email
        username: name
        name: name
        # 认证服务中,登录账号的邮箱,必填
        email: email
        # 认证服务中,登录账号的唯一标识, 必填
        exterId: user_id
    

    修改完成后, 勾选「修改配置后自动重启相关服务」后点击「确认修改配置」。

    开发

    Lark-SSO 对接代码部分会在独立 func 上进行集成开发。

    代码说明

    Oauth2.0服务发现接口

    • 与观测云底座交互的主要集成接口
    import json
    import requests
    
    
    
    @DFF.API('OIDC服务发现接口')
    def well_know():
        '''
        '''
        print("--------turn_token--------------")
        # print(f"--------kwargs--------------\n{kwargs}\n")
        headers = _DFF_HTTP_REQUEST.get("headers", {})
        print(json.dumps(_DFF_HTTP_REQUEST))
        # print(json.dumps(kwargs))
        result = {
            # 这个地址提供原始的 获取登录认证 code 地址
            "authorization_endpoint":"https://open.larksuite.com/open-apis/authen/v1/authorize",
            # code 换 token 接口,此地址需要指向 func 侧对应的 turn_token 函数地址
            # "token_endpoint":"https://gc-func.anta.com/api/v1/al/auln-get-user-token/simplified",
            "token_endpoint":"http://func-server.func:8088/api/v1/sync/auln-get-user-token/simplified",
            # 获取用户信息接口,此地址需要指向 func 侧对应的 turn_userinfo 函数地址
            "userinfo_endpoint":"http://func-server.func:8088/api/v1/sync/auln-get-user-info/simplified",
        }
    
        return result
    

    获取用户token接口

    • 根据 app_id 及 app_secret 获取 tenant_access_token
    • 根据 tenant_access_token 及 用户 access_code 获取 access_token
    import json
    import requests
    
    
    
    
    @DFF.API('获取tenant_access_token接口')
    def get_tenant_access_token():
        '''
        获取访问 token 信息
        '''
        # print(json.dumps(_DFF_HTTP_REQUEST))
        # print(json.dumps(kwargs))
        new_headers = {
            "Content-Type": "application/json; charset=utf-8"
        }
        url = "https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal"
        param = {
            # 替换成 对应的  app_id 及 app_secret  
            "app_id": "cli_xxxxxx",
            "app_secret": "IDxxxxxx",
        }
        resp = requests.post(url, json=param)
        print("========get_tenant_access_token==resp==========")
        print(resp.text)
        # if resp.status_code >= 400:
        #     raise Exception("获取 token 失败")
        result = json.loads(resp.text)
        print("========get_tenant_access_token==result==========")
        tenant_access_token = result["tenant_access_token"]
    
        return tenant_access_token
    
    
    
    @DFF.API('获取用户token接口')
    def turn_token(**kwargs):
        '''
        获取访问 token 信息
        '''
        print("--------turn_token--------------")
        print(f"--------kwargs--------------\n{kwargs}\n")
        headers = _DFF_HTTP_REQUEST.get("headers", {})
        print(json.dumps(_DFF_HTTP_REQUEST))
        print(json.dumps(kwargs))
        tenant_access_token =  get_tenant_access_token()
        new_headers = {
            "content-type": headers.get("content-type"),
            "authorization": f'Bearer {tenant_access_token}'
        }
        url = "https://open.larksuite.com/open-apis/authen/v1/oidc/access_token"
        resp = requests.post(url, data=kwargs, headers=new_headers)
        print("==========resp==========")
        print(resp.text)
        if resp.status_code >= 400:
            raise Exception("获取 token 失败")
        result = resp.json()
        print("==========result==========")
        print(json.dumps(result))
        return result["data"]
    

    获取用户信息接口

    • 根据 用户 access_token 获取用户信息

    注意:此处获取的用户信息,需要确保《Lark - 应用权限配置 》配置正常,否则会无法获取相关的用户信息。

    import json
    import requests
    
    @DFF.API('用户信息获取接口')
    def turn_userinfo(**kwargs):
        '''
        Test hello world function
        '''
        url = "https://open.larksuite.com/open-apis/authen/v1/user_info"
        print("--------turn_userinfo--------------")
        headers = _DFF_HTTP_REQUEST.get("headers", {})
        print(json.dumps(_DFF_HTTP_REQUEST))
        print(json.dumps(kwargs))
        new_headers = {
            "content-type": headers.get("content-type"),
            "authorization": headers.get("authorization")
        }
        resp = requests.get(url, headers=new_headers)
        print("==========resp==========")
        print(resp.text)
        if resp.status_code >= 400:
            raise Exception("获取 用户信息 失败")
        result = resp.json()
        print("==========result==========")
        print(json.dumps(result))
    
        result = result.get("data", {})
        return result
    

    效果

    • 访问观测云主页面,重定向至 Lark 登录访问页面,支持手机号、邮箱、扫码登录,以邮箱访问为例

    • 通过邮箱进行登录访问,跳转应用授权页面

    • 确认授权后,会在管理后台中创建 对应人员账号

    • 将人员添加到对应空间后,重新登录后,可直接跳转至对应空间

    联系我们

    加入社区

    微信扫码
    加入官方交流群

    立即体验

    在线开通,按量计费,真正的云服务!

    立即开始

    选择观测云版本

    代码托管平台