2

我已将身份服务器 3 配置为项目的 IdP,我们有 3 个客户端:MVC Web、IOS 和 Android。一切都对 MVC 应用程序有好处,使用混合流。

对于 IOS 和 Android,使用本机 oidc 客户端(AppAuth IOSAppAuth android)不起作用,即使我将流程配置为 PKCE 混合。

现在,当我尝试使用 Xamarin 在 android 上创建 POC 并使用 IdentityModel.oidcClient 时,一切都按预期工作,获取访问、刷新和 id 令牌。在为 IOS 和 android 使用 AppAuth 时,出现以下错误:

{"type":0,"code":9,"errorDescription":"Response state param did not match request state"}

知道缺少什么吗?

我怀疑这两个本机 oidc 客户端没有要求客户端的共享机密,因此流已损坏。

4

2 回答 2

1

移动应用程序和身份服务器中的数据应该相同,

在服务器上:

new Client
        {
            ClientId = "myClientId",
            ClientName = "myClientName",
            AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,
            RequireConsent = false,

            ClientSecrets =
            {
                new Secret("myClientSecret".Sha256())
            },

            RedirectUris = { "myRedirectUri://callback" },

            AllowedScopes =
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.Email,
                IdentityServerConstants.StandardScopes.Phone,
            },

            AllowOfflineAccess = true
        }

在android中点击登录:

    AuthManager authManager = AuthManager.getInstance(this);
    AuthorizationService authService = authManager.getAuthService();
    Auth auth = authManager.getAuth();

    AuthorizationRequest authRequest = new AuthorizationRequest
        .Builder(
        authManager.getAuthConfig(),
        auth.getClientId(),
        auth.getResponseType(),
        Uri.parse(auth.getRedirectUri()))
        .setScope(auth.getScope())
        .build();

    Intent authIntent = new Intent(this, LoginAuthActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, authRequest.hashCode(), authIntent, 0);

    authService.performAuthorizationRequest(
        authRequest,
        pendingIntent);

索取令牌:

    final AuthorizationResponse resp = AuthorizationResponse.fromIntent(getIntent());
    AuthorizationException ex = AuthorizationException.fromIntent(getIntent());

    final AuthManager authManager = AuthManager.getInstance(this);
    authManager.setAuthState(resp,ex);

    if (resp != null) {

        ClientSecretPost clientSecretPost = new ClientSecretPost(authManager.getAuth().getClientSecret());
        TokenRequest tokenRequest = new TokenRequest
            .Builder(authManager.getAuthConfig(), authManager.getAuth().getClientId())
            .setAuthorizationCode(resp.authorizationCode)
            .setRedirectUri(Uri.parse(authManager.getAuth().getRedirectUri()))
            .build();

        mAuthService = authManager.getAuthService();

        mAuthService.performTokenRequest(tokenRequest, clientSecretPost, new AuthorizationService.TokenResponseCallback() {
            @Override public void onTokenRequestCompleted(@Nullable TokenResponse response, @Nullable AuthorizationException ex) {
                if(ex == null) {
                    authManager.updateAuthState(response,ex);
                    MyApp.Token = authManager.getAuthState().getIdToken();
                    startService(new Intent(LoginAuthActivity.this, TokenService.class));
                    Intent mainIntent = new Intent(LoginAuthActivity.this, MainActivity.class);
                    startActivity(mainIntent);
                    finish();
                }
                else{
                    Intent loginIntent = new Intent(LoginAuthActivity.this, LoginActivity.class);
                    startActivity(loginIntent);
                    finish();
                }
            }
        });

        // authorization completed
    } else {
        // authorization failed, check ex for more details
        Intent loginIntent = new Intent(LoginAuthActivity.this, LoginActivity.class);
        startActivity(loginIntent);
        finish();
    }

AuthManager 类:

public class AuthManager {
private static AuthManager instance;
private AuthState mAuthState;
private Auth mAuth;
private AuthorizationServiceConfiguration mAuthConfig;
private SharedPreferencesRepository mSharedPrefRep;
private AuthorizationService mAuthService;

public static AuthManager getInstance(Context context) {
    if (instance == null) {
        instance = new AuthManager(context);
    }
    return instance;
}

private AuthManager(Context context){
    mSharedPrefRep = new SharedPreferencesRepository(context);
    setAuthData();
    mAuthConfig = new AuthorizationServiceConfiguration(
            Uri.parse(mAuth.getAuthorizationEndpointUri()),
            Uri.parse(mAuth.getTokenEndpointUri()),
            null);
    mAuthState = mSharedPrefRep.getAuthState();

    mAuthService = new AuthorizationService(context);
}



public AuthorizationServiceConfiguration getAuthConfig() {
    return mAuthConfig;
}

public Auth getAuth() {
    if(mAuth == null){
       setAuthData();
    }

    return mAuth;
}

public AuthState getAuthState(){
    return mAuthState;
}

public void updateAuthState(TokenResponse response, AuthorizationException ex){
    mAuthState.update(response,ex);
    mSharedPrefRep.saveAuthState(mAuthState);
}

public void setAuthState(AuthorizationResponse response, AuthorizationException ex){
    if(mAuthState == null)
        mAuthState = new AuthState(response,ex);

    mSharedPrefRep.saveAuthState(mAuthState);
}

public AuthorizationService getAuthService(){
    return mAuthService;
}

private void setAuthData(){
    mAuth = new Auth();
    mAuth.setClientId(BuildConfig.CLIENT_ID);
    mAuth.setAuthorizationEndpointUri(BuildConfig.AUTHORIZSTION_END_POINT_URI);
    mAuth.setClientSecret(BuildConfig.CLIENT_SECRET);
    mAuth.setRedirectUri(BuildConfig.REDIRECT_URI);
    mAuth.setScope(BuildConfig.SCOPE);
    mAuth.setTokenEndpointUri(BuildConfig.TOKEN_END_POINT_URI);
    mAuth.setResponseType(BuildConfig.RESPONSE_TYPE);
}
}

此处的服务将要求刷新令牌。

我已经使用带有 AppAuth-Android 的 Identity Server 4 制作了一个示例,您可以在此处查看

于 2017-07-08T07:03:45.060 回答
0

我们在这里有一个关于 AppAuth-Android 上的混合流支持的未解决问题。这样做的主要问题是混合流不适合移动应用程序,因为每次访问令牌过期时都需要通过 SafariViewController / CustomTab 重复触发 Web 流。获取刷新令牌以允许后台更新访问令牌对于本机应用程序来说更好。

由于 IdentityServer3 是经过认证的 OpenID Connect 实现,您应该能够使用授权代码流来获取刷新令牌。

于 2017-02-13T18:45:56.650 回答