目录

移动应用Authorization Code模式接入华为帐号(OAuth 2.0)

场景介绍

适用于基于HarmonyOS的移动端应用,且希望基于OAuth 2.0协议标准接入华为帐号的场景。

Authorization Code模式基于OAuth 2.0协议标准,应用可以通过获取帐号用户的临时授权票据(Authorization Code),使用户通过帐号安全登录您的应用,首次登录时,要求用户同意授权,当身份验证信息到期时,只需要从服务器端通过刷新令牌刷新访问令牌,从而更快,更可靠,更方便。Authorization Code模式仅适用于有自己服务器的应用。

完整的Authorization Code授权登录流程为:

  1. 移动端应用调用Account SDK的登录接口,获取到授权码Authorization Code(有效期5分钟,且只能使用一次)。
  2. 移动端应用将Authorization Code通过自定义接口发送给应用服务器,应用服务器通过调用华为帐号OAuth服务器的获取凭证Access Token接口,换取Refresh Token和Access Token。
  3. 应用服务器通过使用Access Token参数,调用获取用户信息GOpenUser接口,获取用户信息。

支持的设备

设备类型

OS版本

HMS Core(APK)版本

手机、平板

HarmonyOS 2.0及以上

5.0.0.300及以上

车机

HarmonyOS 2.0及以上

6.2.0.300及以上

华为智慧屏、智能手表(wearable,不支持运动手表liteWearable)

HarmonyOS 2.0及以上

6.5.0.300及以上

HarmonyOS(Java)必须在单HAP包场景下使用,暂不支持多HAP包场景。

开发前提

  1. 请确认您已完成开发准备。
  2. 请确认您的应用有自己的服务器。

帐号登录授权

[h2]登录流程

[h2]客户端开发

  1. 初始化华为帐号SDK。

    在使用华为帐号SDK之前,要求应用先通过调用AccountAuthManager.init(AbilityPackage abilityPackage)方法,完成华为帐号SDK的初始化。

    建议在应用初始化的时候就完成华为帐号SDK的初始化,如下。

    “Java”
    // 示例:在应用初始化时就完成华为帐号SDK的初始化
    public class MyApplication extends AbilityPackage {
        @Override
        public void onInitialize() {
            super.onInitialize();
            // 调用示例initHuaweiAccountSDK方法,在HarmonyOS应用初始化方法onInitialize中进行华为帐号SDK初始化
            initHuaweiAccountSDK();
        }
        @Override
        public void onEnd() {
            super.onEnd();
        }
     
        // 示例:此方法中调用华为帐号SDK的初始化方法AccountAuthManager.init()进行初始化
        private void initHuaweiAccountSDK() {
            Task<Void> task;
            try {
                // 调用AccountAuthManager.init方法初始化
                task = AccountAuthManager.init(this);
            } catch (ApiException apiException) {
                apiException.getStatusCode();
                return;
            }
            task.addOnSuccessListener(new OnSuccessListener<Void>() {
                @Override
                public void onSuccess(Void v) {
                    //初始化成功
                }
            });
     
            task.addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(Exception e) {
                    // SDK初始化失败
                    if (e instanceof ApiException) {
                        ApiException apiException = (ApiException) e;
                        // SDK初始化失败,status code标识了失败的原因,请参见API参考中的错误码了解详细错误原因
                        apiException.getStatusCode();
                    }
                }
            });
        }
    }

  2. 添加登录按钮btn_hwid_sign_in。

    您根据需要在应用布局文件中添加华为帐号登录按钮。

    如您需要使用华为帐号登录图标,请参见华为帐号登录图标使用规范。

  3. 将huaweiIdSignIn绑定到登录按钮ResourceTable.Id_btn_hwid_sign_in的onClick响应事件中,实现华为帐号登录功能。当用户点击登录按钮时,会启动登录视图。

    “Java”
        Button mBtnHuaweiIdSignIn = (Button) findComponentById(ResourceTable.Id_btn_hwid_sign_in);
        mBtnHuaweiIdSignIn.setClickedListener((Component c) -> {
                huaweiIdSignIn();
            });

  4. 调用华为帐号登录接口获取Authorization Code。

    在huaweiIdSignIn方法中,构造登录授权请求参数AccountAuthParams和华为帐号登录授权服务AccountAuthService。

    构造AccountAuthParams参数时,调用AccountAuthParamsHelper.setAuthorizationCode()方法设置使用code模式。

    调用静默登录接口silentSignIn进行静默登录。

    如果静默登录成功,在成功监听中获取华为帐号对象AuthAccount,通过AuthAccount.getAuthorizationCode()获取到授权码Authorization Code;

    如果静默登录失败,需要在静默登录的失败监听中调用前台登录授权signIn接口,显式拉起登录授权视图进行登录,如果前台登录授权接口成功,在成功监听中获取华为帐号对象AuthAccount,通过AuthAccount.getAuthorizationCode()获取到授权码Authorization Code。

     “Java” 
        private void huaweiIdSignIn() {
            AccountAuthService accountAuthService;
            // 1、配置登录请求参数AccountAuthParams,包括请求用户的id(openid、unionid)、email、profile(昵称、头像)等;
            // 2、DEFAULT_AUTH_REQUEST_PARAM默认包含了id和profile(昵称、头像)的请求;
            // 3、如需要再获取用户邮箱,需要setEmail();
            // 4、通过setAuthorizationCode()来选择使用code模式,最终所有请求的用户信息都可以调服务器的接口获取;
            AccountAuthParams accountAuthParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
                    .setAuthorizationCode()
                    .createParams();
            try {
                accountAuthService = AccountAuthManager.getService(accountAuthParams);
            } catch (ApiException e) {
                // 处理初始化登录授权服务失败,status code标识了失败的原因,请参见API参考中的错误码了解详细错误原因
                e.getStatusCode();
                return;
            }
            // 调用静默登录接口。
            // 如果华为系统帐号已经登录,并且已经授权,会登录成功;
            // 否则静默登录失败,需要在失败监听中,显式调用前台登录授权接口,完成登录授权。
            Task<AuthAccount> task = accountAuthService.silentSignIn();
            // 添加静默登录成功处理监听
            task.addOnSuccessListener(new OnSuccessListener<AuthAccount>() {
                @Override
                public void onSuccess(AuthAccount authAccount) {
                    // 静默登录成功后,根据结果中获取到的帐号基本信息更新UI
                }
            });
            // 添加静默登录失败监听
            task.addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(Exception e) {
                    if (e instanceof ApiException) {
                        // 静默登录失败,显式调用前台登录授权接口,完成登录授权。
                        Task task = accountAuthService.signIn();
                        if (task == null) {
                            return;
                        }
                        task.addOnSuccessListener(new OnSuccessListener<AuthAccount>() {
                            @Override
                            public void onSuccess(AuthAccount account) {
                                 // 从account中获取授权码code 
                                 account.getAuthorizationCode();
                            }
                        });
                        task.addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(Exception e) {
                                if (e instanceof ApiException) {
                                    ApiException apiException = (ApiException) e;
                                    // 登录失败,status code标识了失败的原因,请参见API参考中的错误码了解详细错误原因
                                    apiException.getStatusCode();
                                }
                            }
                        });
                    }
                }
            });
        }

[h2]服务端开发

  1. 接收客户端发送过来的code。

    该部分代码需要您根据应用设计自己开发。

  2. 用code换取Access Token和Refresh Token。

    获取到code后调用服务器接口向帐号服务器请求获取Access Token、Refresh Token。接口详细信息请参见获取凭证Access Token,接口调用错误码信息请参见错误码。

    1. 为方便您快速调用接口,华为提供了一个基于Java语言开发的accountservertool.jar,该jar包封装了服务器端相关的rest接口,供您参考或直接使用,如您可以调用jar包中AuthCodeUtil.getTokensByCode(String code,String appId,String appSecret,String redirectUri)方法实现code换取Access Token和Refresh Token操作,详细信息请参见accountservertool.jar工具包使用说明。
    2. code只能使用一次,并且只有5分钟有效期,如出现code过期或者已使用错误码,则需要重新获取code。
    3. 请求参数中使用的redirect_url,请参见设置回调地址进行配置。

  1. 使用Access Token调用获取用户信息接口获取用户信息(昵称、头像、邮箱等)。

    如您使用的是Java语言,accountservertool.jar中提供了AuthCodeUtil.getUserInfos(String accessToken,String getNickName)方法供您使用,详细信息请参见accountservertool.jar工具包使用说明。

    Access Token过期处理

    由于Access Token的有效期(60分钟)较短,当Access Token失效或者即将失效时(可通过NSP_STATUS错误码判断),可以使用Refresh Token(有效期180天)通过获取凭证Access Token接口向帐号服务器请求获取新的Access Token。

    1. 如您使用的是Java语言,accountservertool.jar中提供了AuthCodeUtil.updateAccessToken(String refreshToken,String appId,String appSecret)方法进行access token刷新,详细信息请参见accountservertool.jar工具包使用说明。
    2. 当Access Token失效时,若您不使用Refresh Token向帐号服务器请求获取新的Access Token,帐号的授权信息将会失效,导致使用Access Token的功能都会失败。
    3. 当Access Token非正常失效(如修改密码,退出帐号,删除设备)时,业务可通过调用退出帐号接口后再调用静默登录接口获取新的Access Token。

    RefreshToken过期处理

    由于Refresh Token的有效期为180天,当Refresh Token失效(可通过错误码判断)后,应用服务器需要通知客户端,重新调用Account SDK登录授权接口,请求用户重新授权。

帐号退出

帐号退出是指应用向用户提供可以退出当前华为帐号的入口,应用通过signOut接口通知HMS Core SDK清除本地当前已经登录的华为帐号信息。

  1. 您可以将如下signOut绑定到登出按钮的onClick响应事件中,实现华为帐号退出功能。

    “Java”
            Button mBtnHuaweiIdSignOut = (Button) findComponentById(ResourceTable.Id_btn_signout);
            mBtnHuaweiIdSignOut .setClickedListener((Component c) -> {
                signOut();
            });

  2. 调用AccountAuthService类对象的signOut方法,实现华为帐号退出。

    “Java”
        private void signOut() {
            AccountAuthService accountAuthService = null;
            AccountAuthParams accountAuthParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setEmail().createParams();
            try {
                accountAuthService = AccountAuthManager.getService(accountAuthParams);
            } catch (ApiException e) {
                // 处理初始化登录授权服务失败,status code标识了失败的原因,请参见API参考中的错误码了解详细错误原因
                e.getStatusCode();
                return;
            }
            Task<Void> task = accountAuthService.signOut();
            task.addOnSuccessListener(new OnSuccessListener<Void>() {
                @Override
                public void onSuccess(Void v) {
                    // 华为帐号登出成功,接入应用处理登出后逻辑
                }
            });
     
            task.addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(Exception e) {
     
                    // 华为帐号退出失败
                    if (e instanceof ApiException) {
                        ApiException apiException = (ApiException) e;
                        // 华为帐号退出失败,status code标识了失败的原因,请参见API参考中的错误码了解详细错误原因
                        apiException.getStatusCode();
                    }
                }
            });
        }

取消授权

为了提升应用隐私安全,应用可以提供入口,供用户取消对应用的授权。

取消授权接口通过调用AccountAuthService类对象的cancelAuthorization方法,实现取消授权。

  1. 您可以将如下cancelAuthorization方法绑定到取消授权按钮的onClick响应事件中,实现华为帐号取消授权功能。

    “Java” 
            mBtnCancelAuthorization = (Button) findComponentById(ResourceTable.Id_btn_cancelauthorization);
            mBtnCancelAuthorization.setClickedListener((Component c) -> {
                cancelAuthorization();
            });

  2. 调用AccountAuthService类对象的cancelAuthorization方法,实现华为帐号取消授权功能。

    “Java” 
        private void cancelAuthorization() {
            AccountAuthService accountAuthService;
            AccountAuthParams accountAuthParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setEmail().createParams();
            try {
                accountAuthService = AccountAuthManager.getService(accountAuthParams);
            } catch (ApiException e) {
                // 处理初始化登录授权服务失败,status code标识了失败的原因,请参见API参考中的错误码了解详细错误原因
                e.getStatusCode();
                return;
            }
            // 调用取消授权接口
            Task<Void> task = accountAuthService.cancelAuthorization();
            task.addOnSuccessListener(new OnSuccessListener<Void>() {
                @Override
                public void onSuccess(Void v) {
                    // 取消授权成功
                }
            });
     
            task.addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(Exception e) {
                    // 取消授权失败
                    if (e instanceof ApiException) {
                        ApiException apiException = (ApiException) e;
                        // 华为帐号取消授权失败,status code标识了失败的原因,请参见API参考中的错误码了解详细错误原因
                        apiException.getStatusCode();
                    }
                }
            });
        }