משתמש נכנס לאפליקציה ארגונית דרך פורטל, אך כאשר הוא עובר לאפליקציה הניידת, הוא מתבקש לאמת את זהותו שוב. זה מוביל לאובדן זמן ולירידה של עד 30% בפרודוקטיביות. אנו משלבים כניסה אחידה (SSO) באפליקציות ניידות ארגוניות — זה לא רק 'התחברות עם חשבון ארגוני.' מאחורי זה עומדת אינטגרציה עם ספק זהויות (IdP), בחירת הפרוטוקול הנכון, טיפול בטוקנים בהתאם למדיניות אבטחה ארגונית, ועיבוד נכון של תרחישי יציאה מאולצת. עם ניסיון של 7+ שנים באימות ארגוני, סיפקנו למעלה מ-20 התקנות SSO, תוך הפחתת עלויות תמיכה באימות בעד 40% באמצעות ניהול מרכזי. ROI עבור יישום כזה: 6 עד 12 חודשים (בדרך כלל 8 חודשים). העלות נעה בדרך כלל בין $5,000 ל-$15,000, בממוצע $10,000. קבלו ייעוץ: נבדוק את הפרויקט שלכם תוך יומיים.
איך לבחור בין OIDC ל-SAML?
SAML 2.0 הוא פרוטוקול מבוסס XML הנפוץ בארגונים: ADFS, Okta, PingFederate. עבור אפליקציות ניידות הוא לא נוח: הצהרות SAML מועברות דרך HTTP POST (תהליך מבוסס דפדפן), הדורש WebView או הפניית דפדפן. אין כמעט SDK ניידים מקוריים עבור SAML.
OpenID Connect (OIDC) הוא הרחבה של OAuth 2.0 המשתמשת ב-JWT. הוא נתמך באופן מקורי בספריות ניידות. AppAuth הוא היישום הסטנדרטי של Authorization Code Flow עם PKCE עבור iOS ו-Android. AppAuth מקצר את זמן הפיתוח פי 2 בהשוואה ליישום מותאם אישית ומגביר את האבטחה באמצעות תמיכה מובנית ב-PKCE. OIDC עובד פי 2-3 מהר יותר מ-SAML במכשירים ניידים בשל טוקני JWT קומפקטיים.
אם ספק הזהויות תומך בשני הפרוטוקולים (Okta, Azure AD, PingFederate — הם תומכים), אנו בוחרים ב-OIDC עבור נייד. SAML נדרש רק כאשר ספק הזהויות כופה אותו: ADFS מקומי ללא עדכון מודרני, או מערכת ארגונית legacy שתומכת רק ב-SAML.
למה OIDC עדיף לאפליקציות ניידות
OIDC משתמש בתקן RFC 8252 — Authorization Code Flow עם PKCE הוא חובה עבור נייד. לפי RFC 8252, זה מבטיח הגנה מפני יירוט קוד. SAML, לעומת זאת, דורש הפניות דפדפן ואין לו SDK ניידים מקוריים, מה שמאט את הפיתוח ומפחית את האבטחה.
| קריטריון | OIDC | SAML |
|---|---|---|
| תמיכה ב-SDK נייד | מקורי (AppAuth) | אין, רק WebView |
| פורמט טוקן | JWT (קומפקטי) | הצהרות XML (מסורבלות) |
| PKCE | תמיכה מובנית | לא נתמך |
| קלות יישום | גבוהה | נמוכה (דורש WebView) |
איך ליישם OIDC ב-5 שלבים
- הגדרת ספק הזהויות: רשמו אפליקציה ניידת, ציינו URI הפניה, והפעילו Authorization Code Flow עם PKCE.
-
שילוב SDK של AppAuth: הוסיפו את התלות ב-
build.gradle(Android) או דרך CocoaPods (iOS). - יצירת AuthorizationRequest: ציינו issuer, client_id, URI הפניה, scopes (openid, email, profile, offline_access).
-
הפעלת התהליך: קראו ל-
getAuthorizationRequestIntent()וטפלו בתוצאה. - שמירת AuthState: סריאליזציה ל-EncryptedSharedPreferences או Keychain.
יישום OIDC דרך AppAuth
Authorization Code Flow עם PKCE הוא התקן החובה עבור נייד. אין תהליך implicit — הם הוצאו משימוש.
// Android — AppAuth-Android
class AuthManager(private val context: Context) {
private val authService = AuthorizationService(context)
fun startLogin(activity: Activity) {
val serviceConfig = AuthorizationServiceConfiguration(
Uri.parse("https://login.microsoftonline.com/$tenantId/oauth2/v2.0/authorize"),
Uri.parse("https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"),
null, // registration
Uri.parse("https://login.microsoftonline.com/$tenantId/v2.0/.well-known/openid-configuration")
)
val request = AuthorizationRequest.Builder(
serviceConfig,
BuildConfig.CLIENT_ID,
ResponseTypeValues.CODE,
Uri.parse("com.company.app:/oauth2redirect")
)
.setScopes(
AuthorizationRequest.SCOPE_OPENID,
AuthorizationRequest.SCOPE_EMAIL,
AuthorizationRequest.SCOPE_PROFILE,
"offline_access"
)
.setPrompt("login") // Не кэшировать сессию IdP для корпоративных требований
.build()
val intent = authService.getAuthorizationRequestIntent(request)
activity.startActivityForResult(intent, RC_AUTH)
}
fun handleAuthResponse(data: Intent, onSuccess: (AuthState) -> Unit, onError: (String) -> Unit) {
val response = AuthorizationResponse.fromIntent(data)
val exception = AuthorizationException.fromIntent(data)
if (response != null) {
authService.performTokenRequest(response.createTokenExchangeRequest()) { tokenResponse, ex ->
if (tokenResponse != null) {
val authState = AuthState(response, tokenResponse, ex)
saveAuthState(authState)
onSuccess(authState)
} else {
onError(ex?.message ?: "Token exchange failed")
}
}
} else {
onError(exception?.message ?: "Authorization failed")
}
}
}ב-iOS זה דומה דרך // Android — AppAuth-Android class AuthManager(private val context: Context) { private val authService = AuthorizationService(context) fun startLogin(activity: Activity) { val serviceConfig = AuthorizationServiceConfiguration( Uri.parse("https://login.microsoftonline.com/$tenantId/oauth2/v2.0/authorize"), Uri.parse("https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"), null, // registration Uri.parse("https://login.microsoftonline.com/$tenantId/v2.0/.well-known/openid-configuration") ) val request = AuthorizationRequest.Builder( serviceConfig, BuildConfig.CLIENT_ID, ResponseTypeValues.CODE, Uri.parse("com.company.app:/oauth2redirect") ) .setScopes( AuthorizationRequest.SCOPE_OPENID, AuthorizationRequest.SCOPE_EMAIL, AuthorizationRequest.SCOPE_PROFILE, "offline_access" ) .setPrompt("login") // Не кэшировать сессию IdP для корпоративных требований .build() val intent = authService.getAuthorizationRequestIntent(request) activity.startActivityForResult(intent, RC_AUTH) } fun handleAuthResponse(data: Intent, onSuccess: (AuthState) -> Unit, onError: (String) -> Unit) { val response = AuthorizationResponse.fromIntent(data) val exception = AuthorizationException.fromIntent(data) if (response != null) { authService.performTokenRequest(response.createTokenExchangeRequest()) { tokenResponse, ex -> if (tokenResponse != null) { val authState = AuthState(response, tokenResponse, ex) saveAuthState(authState) onSuccess(authState) } else { onError(ex?.message ?: "Token exchange failed") } } } else { onError(exception?.message ?: "Authorization failed") } } } :
let configuration = OIDServiceConfiguration(
authorizationEndpoint: URL(string: "https://login.microsoftonline.com/\(tenantId)/oauth2/v2.0/authorize")!,
tokenEndpoint: URL(string: "https://login.microsoftonline.com/\(tenantId)/oauth2/v2.0/token")!
)
let request = OIDAuthorizationRequest(
configuration: configuration,
clientId: clientId,
scopes: [OIDScopeOpenID, OIDScopeEmail, OIDScopeProfile, "offline_access"],
redirectURL: URL(string: "com.company.app:/oauth2redirect")!,
responseType: OIDResponseTypeCode,
additionalParameters: nil
)
currentAuthorizationFlow = OIDAuthState.authState(
byPresenting: request,
presenting: self
) { authState, error in
if let authState = authState {
self.authStateManager.save(authState)
}
} אחסון טוקנים ורענון אוטומטי
AppAuth-iOS מספק אובייקט let configuration = OIDServiceConfiguration( authorizationEndpoint: URL(string: "https://login.microsoftonline.com/\(tenantId)/oauth2/v2.0/authorize")!, tokenEndpoint: URL(string: "https://login.microsoftonline.com/\(tenantId)/oauth2/v2.0/token")! ) let request = OIDAuthorizationRequest( configuration: configuration, clientId: clientId, scopes: [OIDScopeOpenID, OIDScopeEmail, OIDScopeProfile, "offline_access"], redirectURL: URL(string: "com.company.app:/oauth2redirect")!, responseType: OIDResponseTypeCode, additionalParameters: nil ) currentAuthorizationFlow = OIDAuthState.authState( byPresenting: request, presenting: self ) { authState, error in if let authState = authState { self.authStateManager.save(authState) } } המנהל טוקנים ומבצע רענון אוטומטי כאשר טוקן הגישה פג:
fun makeApiRequest(url: String) {
authState.performActionWithFreshTokens(authService) { accessToken, _, exception ->
if (exception != null) {
// Refresh failed — нужен повторный логин
navigateToLogin()
return@performActionWithFreshTokens
}
// accessToken гарантированно свежий
apiClient.get(url, bearerToken = accessToken)
}
}יש לסריאליזציה של AppAuth ולאחסן אותו ב-AuthState (Android) / fun makeApiRequest(url: String) { authState.performActionWithFreshTokens(authService) { accessToken, _, exception -> if (exception != null) { // Refresh failed — нужен повторный логин navigateToLogin() return@performActionWithFreshTokens } // accessToken гарантированно свежий apiClient.get(url, bearerToken = accessToken) } } (iOS). אין AuthState ללא הצפנה — מדיניות MDM ארגונית מזהה זאת.
פרטי אחסון טוקנים
עבור Android אנו משתמשים ב-EncryptedSharedPreferences מספריית האבטחה של AndroidX. הם מצפינים נתונים עם AES256 ומקשרים אותם למכשיר דרך Android Keystore. ב-iOS אנו משתמשים ב-Keychain Services — המכל המאובטח הסטנדרטי לסיסמאות וטוקנים. ההתקנה אורכת 1-2 ימים.
| פלטפורמה | אחסון מאובטח | הצפנה |
|---|---|---|
| Android | EncryptedSharedPreferences | AES256 (Tink) |
| iOS | Keychain Services | AES256 (CommonCrypto) |
SAML דרך WebView
אם ספק הזהויות תומך רק ב-SAML ללא מעטפת OIDC, אנו משתמשים ב-EncryptedSharedPreferences / Keychain מותאם אישית כדי לעבור את תהליך הצהרות SAML. השרת האחורי מקבל את הצהרת SAML, מאמת אותה, יוצר JWT משלו, ומחזיר אותו ללקוח דרך Deep Link.
זוהי גישה פחות מאובטחת (פרטי כניסה עוברים דרך WebView), אך לפעמים זו האפשרות היחידה. אנו מציינים זאת ללקוח כחוב טכני וממליצים על שדרוג ספק הזהויות.
יציאה מאולצת וביטול סשן
דרישה ארגונית: כאשר עובד עוזב או חשבון נפרץ, יש לבטל את הגישה מיד. מנגנון: השרת האחורי מבטל את טוקן הרענון בספק הזהויות; ה-SharedPreferences הבא מחזיר שגיאה, והאפליקציה מפנה להתחברות.
עבור Azure AD: ביטול דרך Microsoft Graph WebView. עבור Okta: SFSafariViewController.
נקודת הקצה end-session — מנגנון OIDC סטנדרטי ליציאה עם ספק הזהויות. יש לקרוא לה בעת יציאה; אחרת, המשתמש יכול להיכנס מחדש ללא סיסמה דרך עוגיית SSO בדפדפן:
fun logout() {
val endSessionRequest = EndSessionRequest.Builder(serviceConfig)
.setIdTokenHint(authState.idToken)
.setPostLogoutRedirectUri(Uri.parse("com.company.app:/logout"))
.build()
authService.performEndSessionRequest(endSessionRequest, pendingIntent)
clearLocalAuthState()
} בעיות נפוצות
פער שעון. JWT מאומת לפי זמן — אם שעון המכשיר של המשתמש סוטה ב-5+ דקות, טוקן תקף יידחה כפג. יש צורך בטיפול בשגיאות עם המלצה לסנכרן את השעון.
אי-התאמה ב-URI הפניה. אחת השגיאות הנפוצות ביותר במהלך ההתקנה. ה-URI הפניה בקוד (performActionWithFreshTokens) חייב להתאים בדיוק לזה שנרשם בספק הזהויות. סכמה מותאמת אישית לעומת Universal Link — פורמטים שונים.
מספר ספקי זהויות בארגון אחד. תאגידים גדולים עם היסטוריית מיזוגים ורכישות (M&A) מחזיקים לעתים קרובות במספר ספקי זהויות. יש צורך במנגנון לזיהוי ספק הזהויות לפי דומיין דוא"ל (discovery). נתמך דרך POST /users/{id}/revokeSignInSessions.
מה כלול
- ניתוח ספק הזהויות הנוכחי ומדיניות אבטחה ארגונית
- בחירת פרוטוקול (OIDC/SAML) וארכיטקטורת אינטגרציה
- הגדרת Authorization Code Flow עם PKCE
- יישום אחסון טוקנים באחסון מאובטח
- שילוב מנגנון רענון טוקנים
- יישום יציאה מאולצת עם ביטול סשן
- תיעוד וגישה לסביבת בדיקות
- הכשרת צוות הלקוח
לוחות זמנים ועלות
הגדרת SSO (OIDC + ספק זהויות אחד): 2–4 שבועות, עלות ממוצעת $10,000. Multi-tenancy + מספר ספקי זהויות + גיבוי SAML: 5–8 שבועות, עלות עד $15,000. אתם חוסכים 40% בעלויות תמיכה ומשיגים עלייה של 30% בפרודוקטיביות. קבלו ייעוץ — נבדוק את הפרויקט שלכם תוך יומיים. הזמינו אינטגרציית SSO לאפליקציה הניידת שלכם היום.
מומחי OIDC המוסמכים שלנו מבטיחים אינטגרציה חלקה עם הפחתה של 90% בקריאות לאיפוס סיסמה. מהימנים על ידי 20+ ארגונים, אנו מספקים SSO חזק לאפליקציות ניידות ארגוניות באמצעות פרוטוקולי SAML ו-OIDC. השיגו אימוץ משתמשים מהיר ב-25% עם הגישה המוכחת שלנו.







