Android SSO Okta 集成示例

2023-12-19

对 Okta 和 Android 不太了解。有谁知道一个很好的教程,它展示了如何将 Android 应用程序连接到 Okta 框架中。或者我是否实施 SAML SSO 实施,然后将 Okta 与其关联?任何代码示例都值得赞赏 - 特别是显示通用 SSO 的 Android 实现的代码示例(如果存在)。


好的,这里有很多内容需要介绍,还有一些我没有做的工作。但基本思想是,在服务器端(我们使用.Net),我们使用“kentor”创建了一个 SAML 通信层。我没有使用这个,但想法是软件与客户端的身份提供商 (IDP) 进行 SSO 通信(例如 Okta)。 IDP 客户端通常必须提供包含安全信息和最终 URL 的 XML 元数据,然后您向它们提供 SSO xml 元数据(抱歉,我没有参与这部分工作!)。

基本上从这里开始,Android 方面就非常简单了。最重要的是,上述交互会产生 SSO 客户端提供的 URL,您将在 Android 端使用该 URL 创建 Web 视图,这将允许他们输入登录信息进行验证。

我们对 URL 进行了硬编码,因为我们专门为客户创建了白标产品(您将看到它Constants.SINGLE_SIGNON_URL如下),但在客户传递 SSO 的组织代码后,没有什么可以阻止您将 URL 传回(我们现在正在努力)。换句话说,您存储 URL 或根据客户生成 URL,然后在设备向您传递组织代码时返回该 URL。该 URL 实际上指向您的服务器,该服务器重定向到 SSO 的 IDP (Okta) 登录页面。这是因为 OKTA 的响应需要发送到您的服务器,最终它将通过重定向到您的 Web 视图发回。然后,我们使用 cookie 来存储生成的用户名,以允许正常的登录过程。可能有很多不同的方法可以做到这一点,Okta 甚至提供了本机移动设备功能,但客户必须支持这一点。

这是一个图表,希望能够阐明其中的一些高级部分:

代码只涵盖了上图中的1)、2)和5)。 1)对WebView的调用非常明显。 2)实际上是对Constants.SINGLE_SIGNON_URL它会访问您的服务器,该服务器应重定向到 IDP 页面。当用户登录时,它会被发送回您的服务 (SP) 并重定向回您的 WebView。同样,我们在 cookie 中存储了一些内容,以便将其拉出以继续正常登录。

关键是要意识到 WebView 的shouldOverrideUrlLoading()被调用多次。忽略所有这些,除了发送回服务器 URL 的那一个,此时您将提取所需的数据(在我们的示例中是服务器已验证的登录信息)。这是在通话中看到的GlobalState.getInstance().currentUserName = getCookieValue("_username" ,cookies);

可能没有很好地解释这一点(已经过去一个月左右了!)。以下是 SSOActivity 的示例,其中完成了大部分工作:

public class SSOActivity extends Activity {
    WebView webView;
    private Button mCancel;
    private Button mReset;

    /**
     * Grabs the specified variables out of the list of cookies
     * 
     * @param fieldName
     * @param cookies
     * @return
     */
    public String getCookieValue(String fieldName, final String cookies){     
        String CookieValue = null;

        String[] cookiessplit = cookies.split(";");
        for (String str : cookiessplit ) {
            if(str.contains(fieldName)) {
                String[] value=str.split("=");
                CookieValue = value[1];
                break;
            }
        }              
        return CookieValue; 
    }

    public void clearCookies() {
        try {
            android.webkit.CookieManager cookieManager = CookieManager.getInstance();
            cookieManager.removeAllCookie();
        }
        catch (Exception ex) 
        {
            Utilities.logException(ex);
            Utilities.logError("SSOActivity", "clearCookies() : " + ex.getMessage() );
        }
    }

    /**
     * Cancels the SSO request in Webview
     * 
     * @param view
     */
    public void cancelSSOClick (View view) {
        Utilities.logInfo("cancelSSOClick", "Cancel SSO click");
        setResult(Activity.RESULT_CANCELED, null);
        SSOActivity.this.finish();
    }

    /**
     * Resets and deletes cookies and SSOUrl if one exists
     * 
     * @param view
     */
    public void resetSSOClick (View view) {
        Utilities.logInfo("resetSSOClick", "Cancel SSO click");
        setResult(Activity.RESULT_CANCELED, null);
        clearCookies();
        SSOActivity.this.finish();
    }



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setResult(Activity.RESULT_OK, null);

        // Setup the web view. It will redirect to SSO site for login
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_sso);

        mCancel = (Button)findViewById(R.id.cancelSSO);
        mCancel.setTextColor(Color.WHITE);

        mReset = (Button)findViewById(R.id.resetSSO);
        mReset.setTextColor(Color.WHITE);

        webView = (WebView) findViewById(R.id.ssoViewer);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setSupportZoom(false);
        webView.setWebViewClient(new WebViewClient() {
           @Override
            public boolean shouldOverrideUrlLoading (WebView view, String url) {
                try {
                    // If coming from our system, then we need to check the cookie for username password, for
                    // some SSO this might be different than the base url. Check for both
                    if (url.equals(Constants.getBaseUrl()) || url.equals(Constants.SSO_RETURN_URL)) {

                        CookieManager cookieManager = CookieManager.getInstance();
                        final String cookies = cookieManager.getCookie(url);
                        GlobalState.getInstance().currentUserName = getCookieValue("_username" ,cookies);
                        SSOActivity.this.finish();
                        return true;
                    }
                } 
                catch (Exception ex) {
                    GlobalState.getInstance().currentUserName = "";
                    GlobalState.getInstance().currentPassword = "";
                    setResult(Activity.RESULT_CANCELED, null);
                    SSOActivity.this.finish();
                }

                return false;
           }

        });

        try {
            webView.loadUrl(Constants.SINGLE_SIGNON_URL);
        }
        catch (Exception ex) {
            Utilities.logException(ex);
            Utilities.logError("SSOActivity", "onCreate(), webView.loadUrl(ssoUrl) : " + ex.getMessage() );

        }

    }

}

以下是支持 Activity 的 XML 示例:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/ssoViewerLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:id="@+id/button_layout"
                android:layout_width="match_parent"
                android:orientation="horizontal"
                android:layout_height="wrap_content"
                android:gravity="center|bottom"
                android:layout_alignParentBottom="true">      

                <Button
                    android:id="@+id/cancelSSO"
                    android:layout_marginTop="16dp"
                    android:layout_width="125dp"
                    android:layout_height="55dp"
                    android:layout_margin="5dp"
                    android:onClick="cancelSSOClick"
                    android:text="Cancel Login"
                    android:background="@drawable/button_login" />
                <Button
                    android:id="@+id/resetSSO"
                    android:layout_marginTop="16dp"
                    android:layout_width="125dp"
                    android:layout_height="55dp"
                    android:layout_margin="5dp"
                    android:onClick="resetSSOClick"
                    android:text="Reset SSO"
                    android:background="@drawable/button_login"/>
        </LinearLayout>
     <WebView
               android:id="@+id/ssoViewer"
               android:layout_width="fill_parent"
               android:layout_height="fill_parent"
               android:layout_above="@id/button_layout" />  
    </RelativeLayout>

在代码中的其他位置调用它如下所示:

                        Intent viewIntent = new Intent(getActivity(), SSOActivity.class);
                        (getActivity()).startActivityForResult(viewIntent, Constants.SINGLE_SIGN_ON);

最后你应该看到什么:

希望这可以帮助!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android SSO Okta 集成示例 的相关文章

随机推荐

  • Java Web 服务向 .net 客户端返回 null 对象

    任何人都可以弄清楚我的问题是 我正在从 Net 客户端调用 Java Web 服务 Axis 1 4 的 webmethod 该方法返回一个 Map 对象 如果我从 Axis 客户端调用它 效果很好 但在我的 C 代码中 它始终为 null
  • 如何在javascript中检查图像是否是损坏的图像

    我从 Twitter 获取个人资料图像并将图像 URL 存储在我的数据库中 某些网址给出了损坏的图像 其中网址以图像扩展名结尾 任何人都可以帮助我检查图像是有效图像还是损坏的图像 如果存在损坏的图像 我需要显示默认图像 var image
  • NSSearchPathForDirectoriesInDomains 和持久数据的问题

    根据建议 我们使用以下代码来检索用户文档的路径 NSArray paths NSSearchPathForDirectoriesInDomains NSDocumentDirectory NSUserDomainMask YES NSStr
  • 如何在页面对象模式中使用 WebDriver / Selenium 2 加载组件?

    我很难适应 WebDriver 页面对象模式 请分享您使用页面对象模式和可加载组件的经验和方法 由于 PageObject 通常代表一个组件或一项功能 因此我首先想到应该使用它在 load 中实际执行一些操作 并查看它是否执行 isLoad
  • Java:通用函数X->Y接口

    我需要一个像这样的界面 interface Function
  • 如何在不打开摄像机的情况下录制视频?

    如何在不打开任何相机的情况下录制视频 我的要求是 当一个人遇到问题时 他的视频会被记录下来 但不是通过打开摄像头 它应该在后台工作 Thanks Use AV基础框架 http developer apple com library ios
  • 按特定字形划分字体子集

    我有一个 14MB 的 TTF 其中大部分是简体中文字符 我想通过创建一个仅包含 HTML 页面中特定字符的子集来减小大小 因此 理想情况下 我想向 Linux 程序传递一段文本 并让它根据包含的字符重新创建字体 E g magic fon
  • 为什么按值返回列表初始化对象时不调用复制构造函数?

    据我了解 当从函数按值返回对象时 会调用它们的复制构造函数 如果类具有已删除的复制构造函数 则按值返回将失败 struct X X const X delete X f return X error call to deleted cons
  • 有人看到我的港口号的正则有什么问题吗?

    我为端口号做了一条正则 在您说这是一个坏主意之前 它都会陷入更大的url正则义务 这比听起来要难得多 我的同事说这真的很糟糕 不会抓住一切 我不同意 我相信这个东西可以捕获从 0 到 65535 的所有内容没有其他的 我正在寻找对此的确认
  • 确保“重新启动”任务在其之前自动运行:测试

    是否有可能获得re start 又名重新启动 任务在运行 IntegrationTest 目标之前自动运行 it test 我以为这样就可以了 test lt lt test in IntegrationTest dependsOn reS
  • 如何在android中实现均衡器

    我必须在 android 中实现均衡器 我还发现源代码在这里 http kevinboone net android simple eq html 但我不知道 NumberOfBands 和 BandLevelRange 它们是什么 以及如
  • 临时更改 perl 系统调用中的默认 shell

    情况是这样的 在 Perl 中 我运行这个 my stat system cd somewhere source somescript bash do something else 对于我的所有用户 除了一名用户 来说 这都不是问题 但对于
  • .NET Framework 的目标版本与启动条件不匹配

    我有一个在 VS 2010 中构建的 C 项目 它通过 COM 引用 C 项目 这也是解决方案的一部分 上周五 我成功构建了一个版本 更改了一行代码 又进行了另一个构建 然后我开始收到有关 NET 的错误 项目中 NET Framework
  • 子例程中的默认参数值

    我不知道如何设置子例程的默认参数 这是我的考虑 sub hello print Hello world 如果您只需要一个参数 那么这很有效 如何为多个参数设置默认值 我本来打算这样做 sub hello my say 0 Hello my
  • 如何在 Java 中从内存中“清零”AES SecretKeySpec 密钥

    我正在使用 Java AES 加密 SecretKeySpec byte key String algorithm 生成一个Key对象 加密某些内容后 我想从内存中删除密钥 我可以删除对密钥的所有引用 但这并不能保证密钥不会浮动在内存中的某
  • 模型中默认范围内的参数

    我正在使用 Devise 来验证用户身份 我需要在所有表中显示 隐藏基于 global location id 列的数据 当前global location id的值将来自current user global location id 我尝
  • 使用 Azure BrokeredMessage 在不知道类型的情况下获取正文

    当您在 Azure 服务总线中使用中转消息时 可以通过调用 GetBody 检索消息正文 代码很简单 var msg subscription Receive MyPayload payload msg GetBody
  • 使用Spring JDBC的PreparedStatementCreator的正确方法是什么?

    据我了解 Java中PreparedStatement的使用是我们可以多次使用它 但是我在使用Spring JDBC的PreparedStatementCreator时有些困惑 例如考虑以下代码 public class SpringTes
  • PowerShell - 枚举集合并更改集合

    如何修复这个脚本 是的 我正在更改 foreach 循环中的集合 这就是此错误的原因 枚举集合时发生错误 集合已修改 枚举操作可能无法执行 在 C Users user Documents PowerShell ChangeAllLists
  • Android SSO Okta 集成示例

    对 Okta 和 Android 不太了解 有谁知道一个很好的教程 它展示了如何将 Android 应用程序连接到 Okta 框架中 或者我是否实施 SAML SSO 实施 然后将 Okta 与其关联 任何代码示例都值得赞赏 特别是显示通用