边缘应用OAuth免登对接

更新时间:

1.边缘应用OAuth免登介绍

本章主要介绍部署在边缘集群托管的应用,实现免登及用户信息获取相关流程。

1.1 OAuth免登调用流程

  1. 系统应用环境变量中获取访问域名。System.getenv(“iot.hosting.api.domain”)。

  2. 应用跳转IoT oauth验证地址,同时携带认证后跳转的callback地址。

  3. IoT认证后,携带授权码oauthcode跳转第2步callback的地址。

  4. 应用获取到oauthcode后可以换取accesscode,并通过accesscode获取到用户的完整信息。1

2.实操效果展示

2.1 部署组件

单击组件管理>访问入口 复制IP+端口号,打开新的浏览器页面进行访问,如下图所示:2

2.2 登录边缘控制台

使用“超级账户iotedgeadmin”登录“集群控制台”,用户名与密码一致,首次登录强制修改密码,此连接为内网地址,请保证电脑可以正常连接至内网,如下图所示:3

2.3 查看部署应用

登录成功后,可单击部署应用的应用卡片,进入应用详情,如下图所示:4

2.4 点击应用进行免登

点击部署的应用,直接跳转到应用内部,验证免登,如下图所示:5

3.开发API

3.1 获取应用入口地址

接口描述:

授权类型

APPSIGN

协议

HTTP

请求方法

get

域名(环境变量中获取)

System.getenv(“iot.hosting.api.domain”)

路径

/api/console/app/get

入参说明

入参名称

数据类型

是否必须

入参示例

入参描述

appKey

字符串

21312****

appkey

port

int

80443

请求的服务端口

出参列表

出参名称

数据类型

出参描述

code

整型

响应码, 200: 成功

message

字符串

错误消息

localizedMsg

字符串

本地语言错误消息

data

长整型

响应结果返回为app的相关应用URL

求拼接示例

http://30.42.XX.XX:32187/api/console/app/get?appKey=2813****

请求示例

     /**
     * 获取环境变量和回调的url
     * @return
     */
//iot.hosting.api.schema----是请求协议格式http
private static final String API_GATEWAY_SCHEMA = System.getenv("iot.hosting.api.schema");
//iot.hosting.api.domain--是跳转路径的回调ip地址
private static final String API_GATEWAY_DOMAIN = System.getenv("iot.hosting.api.domain");
//iot.hosting.api.port----是请求端口
private static final String API_GATEWAY_SCHEMA = System.getenv("iot.hosting.api.port");
// iot.hosting.appKey----是请求的appkey
private static final String API_GATEWAY_SCHEMA = System.getenv(" iot.hosting.appKey");
//PATH_APP_GET是请求应用app的响应路径
private static final String PATH_APP_GET = "/api/console/app/get";

@Override
    public String getAppIndex() {
        RequestBuilder builder = RequestBuilder.create(METHOD_GET);
        Map<String, String> queryParams = Maps.newHashMap();
        queryParams.put(PARAM_APP_KEY, appKey);

        builder.setUri(HttpUtils.buildUrl(schema, apiGatewayDomain, apiGatewayPort, PATH_APP_GET, queryParams));

        IoTxResult<AppDTO> result = httpProxy.invoke(
                (HttpRequestBase) builder.build(),
                new TypeReference<IoTxResult<AppDTO>>() {
                }
        );

        logger.info("path={}; params={}; result={}", PATH_APP_GET, JSON.toJSONString(queryParams), JSON.toJSONString(result));

        Assert.assertSuccess(result);
        AppDTO app = result.getData();
        return app.getLoginUrl();
    }

返回结果示例 JSON

{
  {
    "code": 200,
    "data": {
      "aliyunPk": "101248722030****",
      "appKey": "2813****",
      "appMeta": {
        "logoUrl": "http://192.168.11.130:32628/index/28135***",
        "name": "oauth2边缘托管",
        "subVersionId": "1.0",
        "uuid": "937aaa0284864396b54ecadb0d16****",
        "versionUuid": "9ff097f16d8347e6abfcaec0cd14****"
      },
      "appSecret": "NGNiOWQyYzI4MGVhOWNlYmNhOTdmMDIyNTg2MzlhY2Q=",
      "clusterId": "bbeba04d880d49dc80bf83632619341c",
      "configName": "oauth2边缘托管",
      "configUuid": "a7b996cd6ab04b7fb3a54abbc81b****",
      "configVersionUuid": "8e43f4d96bef4a289ad9f9af079d****",
      "loginUrl": "http://192.168.11.130:30313/index",//-----应用登录url
      "name": "Oauth2演示",
      "oauth": {
        "path": "/index",
        "port": 8080,
        "protocol": "",
        "serviceName": "edge",
        "serviceUuid": ""
      },
      "type": "GENERAL_APP",
      "uuid": "731082ac0c444053bad624ec915b****"
    },
    "message": "success"
  }
}

3.2 获取API网关地址

接口描述

授权类型

APPSIGN

协议

HTTP

请求方法

get

域名(环境变量中获取)

System.getenv(“iot.hosting.api.domain”)

路径

/api/console/host/account

入参说明

入参名称

数据类型

是否必须

入参示例

入参描述

chema

字符串

HTTP

请求协议

ports

int

80443

请求的服务端口

url

字符型

/api/console/host/account

请求URL

host

字符型

30.42.XX.XX:32187

请求host

出参列表

出参名称

数据类型

出参描述

code

整型

响应码, 200: 成功

message

字符串

错误消息

localizedMsg

字符串

本地语言错误消息

data

长整型

响应结果

请求拼接示例

http://30.42.XX.XX:32187/api/console/host/account

请求示例

     /**
     *
     * /api/console/host/account
     * @param path
     * @return
     */
    @Override
    public URI getURI(String path) {
        RequestBuilder builder = RequestBuilder.create(METHOD_GET);
        Map<String, String> queryParams = Maps.newHashMap();
        builder.setUri(HttpUtils.buildUrl(schema, apiGatewayDomain, apiGatewayPort, path, queryParams));
        logger.info("RequestBuilder请求url");
        IoTxResult<String> result = httpProxy.invoke(
                (HttpRequestBase) builder.build(),
                new TypeReference<IoTxResult<String>>() {

                }
        );
        logger.info("path={}; params={}; result={}", path, JSON.toJSONString(queryParams), JSON.toJSONString(result));
        Assert.assertSuccess(result);
        try {
            return new URI(result.getData());
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

返回结果示例 JSON

{
    "code": 200,
    "data": {
        "oauth": {
        "path": "/index",
        "port": 32187,
         "host":30.42.XX.XX
        "protocol": "",
        "serviceName": "edge",
        "serviceUuid": ""
      },
      "type": "GENERAL_APP",
      "uuid": "731082ac0c444053bad624ec915b****"
    },
    "message": "success"
  }

3.3 发起免登验证

接口描述

授权类型

APPSIGN

协议

HTTP

请求方法

get

域名(环境变量中获取)

System.getenv(“iot.hosting.api.domain”)

路径

/oauth2/auth

入参说明

入参名称

数据类型

是否必须

入参示例

入参描述

client_id

String

2813****

应用的appkey

redirect_uri

String

http://30.42.XX.XX:32187/index

OAuth认证通过后的重定向应用的URI,包含完整的域名

response_type

String

code

返回类型。根据OAuth 2.0标准,目前支持设置此参数的取值为code

state

String

2813****

应用的appkey携带项

scope

String

空格分隔的OAuth范围列表。如不指定此参数取值,则默认为应用注册的全部OAuth范围,加上scopid

出参列表

出参名称

数据类型

出参描述

code

整型

响应码, 200: 成功

message

字符串

错误消息

localizedMsg

字符串

本地语言错误消息

data

长整型

响应结果

请求拼接示例

http://30.42.XX.XX:32187/oauth2/auth? 
 redirect_uri=http://30.42.XX.XX:32187/index&
 client_id=28135051&state=28135051&
 response_type=code

请求示例

    /**
     *获取免登url和code
     * @param appKey
     * @param redirectUri
     * @return
     */
    public String getLoginRedirectUrl(String appKey, String redirectUri) {
        Map<String, String> queryParams = Maps.newHashMap();
        queryParams.put(PARAM_CLIENT_ID, appKey);
        queryParams.put(PARAM_REDIRECT_URI, redirectUri);
        queryParams.put(PARAM_RESPONSE_TYPE, "code");

        URI accountUri = getAccountUri();

        return HttpUtils.buildUrl(
                schema,
                accountUri.getHost(),
                accountUri.getPort(),
                PATH_LOGIN,
                queryParams).toASCIIString();
    }

返回结果示例 JSON

http://30.42.XX.XX:32187/index?code=64a67ee15534defea7ad0d0535189b24&state=28135051

3.4 换取accessToken

接口描述

授权类型

ANONYMOUS

协议

HTTP

请求方法

post

域名(环境变量中获取)

System.getenv(“iot.hosting.api.domain”)

路径

/user/oauth2/token/get

入参说明

入参名称

数据类型

是否必须

入参描述

code

字符串

初始请求中获取的授权码

grant_type

字符串

根据OAuth 2.0标准, 取值为authorization_code

redirect_uri

字符型

初始authorization请求中设置的redirect_uri参数

client_id

字符型

应用的appkey

出参列表

出参名称

数据类型

出参描述

code

整型

响应码, 200: 成功

message

字符串

错误消息

localizedMsg

字符串

本地语言错误消息

data

长整型

响应结果

请求示例

    /**
     * 根据code获取到token
     * @param appKey
     * @param oauthCode
     * @return
     */
    public String getAccessTokenByOauthCode(String appKey, String oauthCode) {
        RequestBuilder builder = RequestBuilder.create(METHOD_GET);

        Map<String, String> queryParams = Maps.newHashMap();
        queryParams.put(PARAM_CODE, oauthCode);
        queryParams.put(PARAM_GRANT_TYPE, "authorization_code");
        queryParams.put(PARAM_CLIENT_ID, appKey);

        URI accountUri = getAccountUri();
        builder.setUri(HttpUtils.buildUrl(accountUri.getScheme(), accountUri.getHost(), accountUri.getPort(), PATH_GET_ACCESS_TOKEN_BY_OAUTH_CODE, queryParams));

        IoTxResult<AccessTokenDTO> result = httpProxy.invoke(
                (HttpRequestBase) builder.build(),
                new TypeReference<IoTxResult<AccessTokenDTO>>() {
                }
        );

        PROXY_LOGGER.info("path={}; params={}; result={}", PATH_GET_ACCESS_TOKEN_BY_OAUTH_CODE, JSON.toJSONString(queryParams), JSON.toJSONString(result));

        Assert.assertSuccess(result);

        AccessTokenDTO accessTokenDTO = result.getData();
        Assert.assertNotNull(accessTokenDTO, "get accessToken failed");
        return accessTokenDTO.getAccessToken();
    }

返回结果示例 JSON

{
    "code": 200,
    "data": {
        "access_token": "agasdfagdsafasdf",
        "expired_time": 21232,
        "refresh_token": "asdgadgasfadsaf",
        "token_type": "Bearer",
        "open_id": "gasdfasdfasdf"
    },
    "id": "246da69e-40ad-4f44-955e-ac880f9867d7"
}

3.5 获取用户信息

接口描述

授权类型

ANONYMOUS

协议

HTTP

请求方法

post

域名(环境变量中获取)

System.getenv(“iot.hosting.api.domain”)

路径

/user/oauth2/userinfo/get

入参说明

入参名称

数据类型

是否必须

入参示例

入参描述

access_token

String

3123qwqrqwq

访问令牌

出参列表

出参名称

数据类型

出参描述

code

整型

响应码, 200: 成功

message

字符串

错误消息

localizedMsg

字符串

本地语言错误消息

data

长整型

响应结果

请求示例

   /**
     * 根据token获取用户信息
     * @param accessToken
     * @return
     */
    public UserInfoDTO getUserInfoByAccessToken(String accessToken) {
        RequestBuilder builder = RequestBuilder.create(METHOD_GET);

        Map<String, String> queryParams = Maps.newHashMap();
        queryParams.put(PARAM_ACCESS_TOKEN, accessToken);

        URI accountUri = getAccountUri();
        builder.setUri(HttpUtils.buildUrl(accountUri.getScheme(), accountUri.getHost(), accountUri.getPort(), PATH_GET_USER_INFO_BY_ACCESS_TOKEN, queryParams));

        IoTxResult<UserInfoDTO> result = httpProxy.invoke(
                (HttpRequestBase) builder.build(),
                new TypeReference<IoTxResult<UserInfoDTO>>() {
                }
        );

        PROXY_LOGGER.info("path={}; params={}; result={}", PATH_GET_USER_INFO_BY_ACCESS_TOKEN, JSON.toJSONString(queryParams), JSON.toJSONString(result));

        Assert.assertSuccess(result);

        UserInfoDTO userInfoDTO = result.getData();
        Assert.assertNotNull(userInfoDTO, "get userInfo failed");

        return userInfoDTO;
    }

返回结果示例 JSON

 "id": "246da69e-40ad-4f44-955e-ac880f9867d7",
    "code": 200,
    "message": null,
    "localizedMsg": null,
    "data": {
        "open_id": "eaef01f7bfaf0b7a95366720d58d1fd5",
        "name": "test",
        "phone": "1381234****",
        "tenant_open_id": "1c8c23f0adef8bd04fa166372b781f0d",
        "tenant_name": "test"
    }

3.6 Token有效性判断

接口描述

授权类型

ANONYMOUS

协议

HTTP

请求方法

post

域名(环境变量中获取)

System.getenv(“iot.hosting.api.domain”)

路径

/user/oauth2/accesstoken/check

入参说明

入参名称

数据类型

是否必须

入参示例

入参描述

access_token

String

3123qwqrqwq

访问令牌

出参列表

出参名称

数据类型

出参描述

code

整型

响应码, 200: 成功

message

字符串

错误消息

localizedMsg

字符串

本地语言错误消息

data

长整型

响应结果

请求示例

   /**
     * token登录有效期检查
     * @param token
     * @return
     */
    public boolean checkLogin(String token) {
        RequestBuilder builder = RequestBuilder.create(METHOD_GET);

        Map<String, String> queryParams = Maps.newHashMap();
        queryParams.put(PARAM_ACCESS_TOKEN, token);

        URI accountUri = getAccountUri();
        builder.setUri(HttpUtils.buildUrl(accountUri.getScheme(), accountUri.getHost(), accountUri.getPort(), PATH_LOGINCHECK, queryParams));

        IoTxResult<Boolean> result = httpProxy.invoke(
                (HttpRequestBase) builder.build(),
                new TypeReference<IoTxResult<Boolean>>() {
                }
        );

        PROXY_LOGGER.info("path={}; params={}; result={}", PATH_LOGINCHECK, JSON.toJSONString(queryParams), JSON.toJSONString(result));

        Assert.assertSuccess(result);
        return result.getData();
    }

返回结果示例 JSON

 {
    "code": 200,
    "data": {
        "result":true
    },
}