账号及用户 SDK

更新时间:2018-08-23 15:50:30

概述

账号和用户 SDK,提供账号能力,包括注册,登录,登出,获取账号,会话管理,人机校验,UI定制,以及基于 iotToken的用户身份认证功能。

账号和用户SDK主要包含两个sdk:登录sdk和身份认证sdk,在初始化账号和用户SDK之前,必须要先初始化API通道SDK,请参见 API 通道 - 初始化。

依赖SDK 概述
API 通道 提供API通道能力

1. 登录SDK :

提供账号能力,包括注册,登录,登出,获取账号,会话管理,人机校验,UI定制。

推荐使用DemoAPP中提供的OALoginAdapter,里面封装了针对登录相关的操作。

1.1 初始化

  1. 如果使用OALoginAdapter,初始化代码如下
//如果com.aliyun.iot.aep.sdk:account 为0.0.2以及以上,请使用如下代码完成初始化
OALoginAdapter adapter = new OALoginAdapter(application);
adapter.init("online");
LoginBusiness.init(application,adatper,true,"online");


//如果com.aliyun.iot.aep.sdk:account 为0.0.2以下,请使用如下代码完成初始化
OALoginAdapter adapter = new OALoginAdapter(application);
LoginBusiness.init(application,adatper,true,"online");
  1. 如果不使用OALoginAdapter,需要自己实现ILoginAdapter接口,直接调用SDK级接口完成初始化(初始化为异步初始化,调用后会立即返回),初始化代码片段如下:
//如果不使用OALoginAdapter,可以直接调用底层SDK提供的接口
/**
  * 设置当前的环境信息 -- 只支持线上环境
  * Environment.ONLINE 线上
 **/
ConfigManager.getInstance().setEnvironment(Environment.ONLINE);
//设置图片后缀
ConfigManager.getInstance().setSecGuardImagePostfix("114d");
//设置使用单张图片
ConfigManager.getInstance().setUseSingleImage(true);
//使用API网关
ConfigManager.getInstance().setAPIGateway(true);

//打开调试,会有详细日志输出
OpenAccountSDK.turnOnDebug();

//调用异步初始化
OpenAccountSDK.asyncInit(getApplicationContext(), new InitResultCallback() {
    @Override
    public void onSuccess() {
        ToastUtil.show(getApplicationContext(), "OpenAccountSDK 初始化成功");
    }

    @Override
    public void onFailure(int code, String msg) {
        ToastUtil.show(getApplicationContext(), "OpenAccountSDK 初始化失败 : " + msg);
    }
});

OpenAccountSDK 提供的接口,可以参见 API Doc

LoginBusiness为统一登录抽象接口,关于账号相关的操作,统一通过LoginBusiness暴露给上层业务方。

请注意,如果不使用OALoginAdapter,那么需要自己实现ILoginAdapter接口,并且初始化LoginBusiness。
LoginBusiness初始化方法为

/**
 * 初始化
 *
 * @param adapter 自定义,实现ILoginAdapter,不能为NULL
 * @param isDebug 是否开启adapter内部调试开关
 * @param env     当前APP的环境,目前仅支持 线上环境,入参为"ONLINE"
 */
public static void init(Context context, ILoginAdapter adapter, boolean isDebug, String env);

1.2 使用方式(使用默认OALoginAdapter)

使用之前必须完成LoginBusiness的初始化

* 登录

打开登录页面方法为:

 /**
  * 登录
  *
  * @param callback 登录结果回调
  */
public static void login(ILoginCallback callback)

* 退出登录

退出登录方法为:

/**
 * 登出
 *
 * @param callback 登出结果回调
 */
public static void logout(ILogoutCallback callback);

* 刷新会话

刷新Session的方法为:

/**
 * 刷新当前会话
 *
 * @param force                  是否需要强刷当前会话
 * @param refreshSessionCallback 刷新Session监听回调接口
 */
public static void refreshSession(boolean force, IRefreshSessionCallback refreshSessionCallback);

* 获取会话ID

获取SessionID的方法为:

/**
 * 获取当前会话ID
 */
public static String getSessionId();

* 获取用户信息

获取用户信息的方法为:

/**
 * 返回用户信息
 *
 * @return 登录用户信息
 */
public static UserInfo getUserInfo();

其中UserInfo定为如下:

public class UserInfo {
    /**
     * 用户ID
     */
    public String userId;

    /**
     * 用户昵称
     */
    public String userNick;

    /**
     * 用户头像
     */
    public String userAvatarUrl;

    /**
     * 用户手机号
     */
    public String userPhone;
}

1.3 使用方式(实现ILoginAdapter)

如果不使用OALoginAdapter,需要自行实现ILoginAdapter,直接调用底层SDK接口

* 登录

打开登录页面代码片段如下

OpenAccountUIService openAccountService = OpenAccountSDK.getService(OpenAccountUIService.class);
try {
    openAccountService.showLogin(context, new LoginCallback() {
       @Override
        public void onSuccess(OpenAccountSession openAccountSession) {
            ToastUtil.show(getApplicationContext(), "登录成功");   
        }

        @Override
        public void onFailure(int i, String s) {
              ToastUtil.show(getApplicationContext(), "登录失败");  
        }
    });
} catch (Exception e) {
        ToastUtil.show(getApplicationContext(), "登录异常 : " + e.toString());
    }
}

* 退出登录

退出登录代码片段如下:

OpenAccountService openAccountService = OpenAccountSDK.getService(OpenAccountService.class);
try {
       openAccountService.logout(context, new LogoutCallback() {
       @Override
       public void onSuccess() {
           ToastUtil.show(getApplicationContext(), "登出成功");     
       }

       @Override
       public void onFailure(int i, String s) {
                ToastUtil.show(getApplicationContext(), "登出失败 : " + s);
          }
       });
} catch (Exception e) {
     ToastUtil.show(getApplicationContext(), "登出异常 : " + e.toString());
    }
}

* 会话(Session)管理

刷新会话代码片段如下:

OpenAccountSessionService openAccountSessionService = OpenAccountSDK.getService(OpenAccountSessionService.class);
openAccountSessionService.refreshSession(true);

获取会话信息代码片段如下:

SessionManagerService sessionManagerService = OpenAccountSDK.getService(SessionManagerService.class);
if (sessionManagerService == null) {
    return;
}
OpenAccountSession session = sessionManagerService.getSession();

其中 OpenAccountSession常用方法定义如下:

public interface OpenAccountSession {
    /**
     * 标识当前会话是何种场景下创建
     */
    int getScenario();

    /**
     * 是否登录
     */
    boolean isLogin();

    /**
     * 获取用户ID
     */
    String getUserId();

    /**
     * 获取用户信息
     */
    User getUser();

    /**
     * 如果是三方账号对接,这里返回三方账号的信息
     */
    Map<String, Object> getOtherInfo();
}

User结构定义如下:

public class User {
    /**
     * 用户 Id
     */
    public String id;

    /**
     * 用户昵称
     */
    public String nick;

    /**
     * 用户头像
     */
    public String avatarUrl;

    /**
     * 用户手机号
     */
    public String mobile;

    /**
     * 手机号前缀
     */
    public String mobileLocationCode;

    /**
     * 是否设置密码
     */
    public boolean hasPassword;

    /**
     * openId 如果使用三方授权登录,第三方账号的 id 信息
     */
    public String openId;

    /**
     * 用户扩展信息
     */
    public Map<String, Object> otherInfo;
}

1.4 三方自有账号接入

主要步骤如下:

  • 完成SDK的初始化,参考1.1节关于SDK初始化的部分

  • 强烈建议在对接三方自有账号之前,确认默认的账号页面可以正常的注册和登录

  • 自有账号通过OAuth2.0协议介入,做好服务端的配置,流程请参考 账号及用户服务配置

  • 自己开发三方账号登录页面

    注意:

以上工作完成之后,在三方账号登录成功之后,通过以下接口完成OAuth登录

 OpenAccountService service = OpenAccountSDK.getService(OpenAccountService.class);

 service.authCodeLogin(OALoginActivity.this, authCode, new LoginCallback() {
    @Override
        public void onSuccess(OpenAccountSession openAccountSession) {
            Toast.makeText(getApplicationContext(), "auth 授权登录 成功  ", Toast.LENGTH_SHORT).show();
        }

    @Override
        public void onFailure(int code, String msg) {
             Toast.makeText(getApplicationContext(), "auth授权登录 失败 code = " + code + " message = " + msg, Toast.LENGTH_SHORT).show();
        }
  });

1.5 注意事项

  • 自行实现ILoginAdapter或者使用三方账号登录时,请务必注意在登录或者登出时,必须处理通过ILoginAdapter.registerLoginListener()设置的listener,以保证其他基础SDK可以监听到登录状态。

  • 参考代码如下:
    ```
    //打开登录页面
    OpenAccountUIService openAccountService = OpenAccountSDK.getService(OpenAccountUIService.class);
    openAccountService.showLogin(context, new OALoginCallback(callback));

//三方auth登录
OpenAccountService service = OpenAccountSDK.getService(OpenAccountService.class);
service.authCodeLogin(context, autoCode, new OALoginCallback(callback));

//退出登录
OpenAccountService openAccountService = OpenAccountSDK.getService(OpenAccountService.class)
openAccountService.logout(context, new OALogoutCallback(callback));

其中两个Callback定义如下:

private List mLoginStatusChangeListenerList = new ArrayList<>();

public class OALoginCallback implements LoginCallback {
public ILoginCallback loginCallback;

public OALoginCallback(ILoginCallback loginCallback) {
    this.loginCallback = loginCallback;
}

@Override
public void onSuccess(OpenAccountSession openAccountSession) {
    for (ILoginStatusChangeListener listener : mLoginStatusChangeListenerList) {
        listener.onLoginStatusChange();
    }
    if (loginCallback != null) {
        loginCallback.onLoginSuccess();
    }
}

@Override
public void onFailure(int i, String s) {
    if (loginCallback != null) {
        loginCallback.onLoginFailed(i, s);
    }
}

}

private class OALogoutCallback implements LogoutCallback {
private ILogoutCallback logoutCallback;

public OALogoutCallback(ILogoutCallback logoutCallback) {
    this.logoutCallback = logoutCallback;
}

@Override
public void onFailure(int code, String msg) {
    if (logoutCallback != null) {
        logoutCallback.onLogoutFailed(code, msg);
    }
}

@Override
public void onSuccess() {
    for (ILoginStatusChangeListener listener : mLoginStatusChangeListenerList) {
        listener.onLoginStatusChange();
    }

    if (logoutCallback != null) {
        logoutCallback.onLogoutSuccess();
    }
}

}


## <a name="hgkrps"></a>1.5 自定义UI
请参考 [UI界面自定义](https://baichuan.taobao.com/docs/doc.htm?spm=a3c0d.7629140.0.0.Nkab7a&treeId=40&articleId=103007&docType=1) 一文

## <a name="qlwxwr"></a>1.6 混淆配置
```proguard

-keep class com.alibaba.sdk.android.*

-keep class com.aliyun.iot.aep.sdk.login.**{*;}

2. 身份认证SDK

提供基于 iotToken 的用户身份认证方案,通过和账号 SDK、API 通道 SDK 的集成,完成用户身份凭证的生成和管理,以及发起 API 请求的用户身份的鉴权。

2.1 初始化

身份认证SDK的初始化,必须在账号SDK初始化之后

SDK(com.aliyun.iot.aep.sdk:iot-credential)版本小于0.0.1.7,初始化接口定义如下:

/**
 * 初始化IoTCredentialManageImpl
 *
 * @param loginAdapter 实现统一登录抽象接口,不可以为NULL
 * @param appKey       平台注册的APPKEY
 */
public static void init(ILoginAdapter loginAdapter, String appKey);


//常用初始化代码片段:
OALoginAdapter loginAdapter = new OALoginAdapter(context);
IoTCredentialManageImpl.init(loginAdapter, appkey);

SDK(com.aliyun.iot.aep.sdk:iot-credential)版本为0.0.1.7以及以上,初始化接口定义如下:

/**
 * 初始化IoTCredentialManageImpl
 *
 * @param loginAdapter 实现统一登录抽象接口,不可以为NULL
 * @param appKey       平台注册的APPKEY
 */
public static void init(String appKey);

//常用初始化代码片段:
IoTCredentialManageImpl.init(appKey);

2.2 使用方式

当使用 API 通道 执行某些需要IoT身份鉴权的业务请求时,统一身份认证 SDK 为 API 通道提供了一个自动完成请求认证信息填充的模块 IoTCredentialProviderImpl,使用方式如下:

  1. 初始化IoTCredentialHook模块代码如下:

    IoTAuthProvider provider = new IoTCredentialProviderImpl(IoTCredentialManageImpl.getInstance(app));
    IoTAPIClientImpl.getInstance().registerIoTAuthProvider("iotAuth", provider);
    
  2. 构建需要鉴权的业务请求 IoTRequest

构建 IoTRequest 时需要增加 AuthType 参数(参数填写注册 IoTCredentialHook 时,注册的 key,本例为“iotAuth”) ,代码如下所示:

IoTRequest request = new IoTRequestBuilder()
    .setPath("path")
    .setApiVersion("1.0.4")
    .addParam("request", paramMap)
    .setAuthType("iotAuth")
    .build();

在 API 通道内部会触发 IoTCredentialProviderImpl ,自动刷新并填充认证信息,完成正常的业务请求。

2.3 其他功能说明:

* 获取用户凭证(iotToken)

获取用户认证数据代码片段如下,如果结果返回NULL,可以调用异步刷新接口重新获取

IoTCredentialManage ioTCredentialManage = IoTCredentialManageImpl.getInstance(app);
if(ioTCredentialManage!=null){
    ioTCredentialManage.getIoTCredential();
}

* 刷新用户凭证(iotToken)

刷新用户认证数据代码片段如下:

IoTCredentialManage ioTCredentialManage = IoTCredentialManageImpl.getInstance(app);
if (ioTCredentialManage != null) {
    ioTCredentialManage.asyncRefreshIoTCredential(new IoTCredentialListener() {
        @Override        
        public void onRefreshIoTCredentialSuccess(IoTCredentialData ioTCredentialData) {
            Log.i(TAG, "refresh IoTCredentailData success :" + ioTCredentialData.toString());
        }

        @Override
        public void onRefreshIoTCredentialFailed(IoTCredentialManageError ioTCredentialManageError) {
            Log.i(TAG, "refresh IoTCredentailData failed ");
            if (ioTCredentialManageError != null) {
                Log.i(TAG, "error code is:" + ioTCredentialManageError.errorCode);
            }
        }
    });
}

2.4 混淆配置:


-keep public class com.aliyun.iot.aep.sdk.credential** {
    public <methods>;
    public <fields>;
}

常见问题说明:

问题1 : 执行登录或者注册时,提示“亲,您的手机网络不太顺畅哦~”

排查步骤:

  • 确认安全图片是否在src/drawable目录下,如果在在初始化代码中设置了图片后缀为“114d”,请务必保证安全图片的名称为yw_1222_114d;

      //设置图片后缀
      ConfigManager.getInstance().setSecGuardImagePostfix("114d");
    
  • 确认初始化中是否有抛出异常

    • 其中ErrorCode=110的异常码可以忽略
    • 以下几种Warn可以忽略(用来检查社交账号SDK)
      W/oa_Oauth: [] : Umeng is not available, Umeng Oauth Service Provider is disabled
      W/oa_Oauth: [] : Taobao MemberSDK is not available, Taobao 3rd Oauth Service Provider is disabled
      W/oa_Oauth: [] : Taobao login4android SDK is not available, Taobao 2nd Oauth Service Provider is disabled
      W/oa_Oauth: [] : Alipay sdk is not available, Alipay Oauth Service Provider is disabled
      
  • 如果是用Demo中提供的OALoginAdapter,下面异常日志可以忽略

      java.lang.NullPointerException: Attempt to invoke virtual method 'long java.lang.Long.longValue()' on a null object reference
      at com.aliyun.iot.aep.sdk.login.oa.OALoginAdapter.a(OALoginAdapter.java:343)
    

问题2 : 无法打开登录页面

排查步骤:

  • 确认日志中是否有以下异常输出
      init failed code = 10010 message = 发生错误,消息为 null, 请使用 LogCat 查看更多细节
      或者
      Failed resolution of: Lcom/ut/mini/UTHitBuilders@UTCustomHitBuilder
    

说明主工程缺少UT SDK的依赖,请在主工程里增加如下两个依赖,或者在平台上重新下载SDK依赖文件:

  •     compile 'com.aliyun.ams:alicloud-android-utdid:1.1.5.4'
        compile 'com.aliyun.ams:alicloud-android-ut:5.1.0'
    

问题3:无法正常获取iotToken,或者调用接口时返回认证错误

排查步骤: 请根据接口返回的异常信息(例如errorCode的值)判断,错误码定义如下:

/**
 * 账号未登录,需要登录
 */
public static final int RESULT_CODE_NOT_LOGIN = 0;

/**
 * 账号类型错误, accountType 需要和一站式开发平台配置保持一致
 */
public static final int RESULT_CODE_ACCOUNT_TYPE_INVALID = 1;

/**
 * 账号 authCode 无效
 */
public static final int RESULT_CODE_AUTHCODE_INVALID = 2;

/**
 * 服务器返回 refreshToken 过期或无效,需要重新登录
 */
public static final int RESULT_CODE_REFRESHTOKEN_INVALID = 3;

/**
 * 服务器响应的报文格式异常 ,请提工单
 */
public static final int RESULT_CODE_WRONG_RESPONSE_FORMAT = 4;

/**
 * 账号 authCode 校验失败,如果重新登录再请求还报同样的错误码,请提工单
 */
public static final int RESULT_CODE_AUTHCODE_CHECK_FAILED = 5;

/**
 * 其他错误,如,网络错误或服务器返回的错误,会把原始错误信息通过 userInfo.detail 透传
 */
public static final int RESULT_CODE_OHTER = -1;

问题4 : 刷新IoTToken一直提示错误

排查步骤:

  • 确认是否有同一个账号多端登录,目前的认证系统不支持同一个账号多端登录,后登录的设备会将之前登录的设备踢掉,表现为:刷新IoTToken一直失败,返回错误码为3,详情请参考问题3的错误码描述。

  • 确认是否登录,确认在实现ILoginAdapter时,是否有实现refreshSession接口(当登录态失效时,身份认证SDK会调用ILoginAdapter.refreshSession来刷新)。

  • 其他错误码请参考问题3

results matching ""

    No results matching ""