Как выполнить OAuth с помощью ключа OpenID в клиенте Android

#android #keycloak #aerogear

#Android #скрытый ключ #aerogear

Вопрос:

Я хочу аутентифицировать пользователя (используя его имя пользователя и пароль) в приложении для Android, используя aerogear, с сервером, использующим Keycloak. Я не смог этого сделать, помогите мне, пожалуйста.

В настоящее время я могу аутентифицировать пользователя без aerogear, но я хочу использовать эту библиотеку, поскольку она может помочь мне обновить токен, когда это необходимо. Я аутентифицирую пользователя, выполняющего POST-вызов на сервер следующим образом (но с Android).:

  curl -X POST http://127.0.0.1:8080/auth/realms/example/protocol/openid-connect/token  
 -H "Content-Type: application/x-www-form-urlencoded" -d "username=auser" -d 'password=apassword' -d 'grant_type=password' 
 -d 'client_id=clientId' -d 'client_secret=secret'
  

Итак, информация, которой я располагаю, такова:

  • URL аутентификации, ie http://127.0.0.1:8080/auth/realms/example/protocol/openid-connect/token
  • имя пользователя, имя пользователя пользователя
  • пароль, пароль пользователя
  • client_id и client_secret сервера перехвата ключей

То, что я пробовал с Aerogear, это:

 private void authz() {
    try {

        AuthzModule authzModule = AuthorizationManager.config("KeyCloakAuthz", OAuth2AuthorizationConfiguration.class)
                .setBaseURL(new URL("http://127.0.0.1:8080/"))
                .setAuthzEndpoint("/realms/example/protocol/openid-connect/auth")
                .setAccessTokenEndpoint("/realms/example/protocol/openid-connect/token")
                .setAccountId("keycloak-token")
                .setClientId("clientId")
                .setClientSecret("secret")
                .setRedirectURL("http://oauth2callback")
                .setScopes(Arrays.asList("openid"))
                .addAdditionalAuthorizationParam((Pair.create("grant_type", "password")))
                .addAdditionalAuthorizationParam((Pair.create("username", "aUserName")))
                .addAdditionalAuthorizationParam((Pair.create("password", "aPassword")))
                .asModule();


        authzModule.requestAccess(this, new Callback<String>() {
            @Override
            public void onSuccess(String o) {
                Log.d("TOKEN ", o);
            }

            @Override
            public void onFailure(Exception e) {
                System.err.println("Error!!");
                Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
            }
        });

    } catch (Exception e) {

        e.printStackTrace();
        throw new RuntimeException(e);
    }
}
  

Однако это ничего не дает. Чего я не понимаю, так это:

  1. Как я могу указать, что я делаю, и OpenID подключается к Keycloak в Aerogear?
  2. Как и куда я могу отправить имя пользователя и пароль?
  3. Как я могу указать grant_type? (Мой HTTP-ПОСТ на сервер не будет работать, если я не включу это, так что это важно)

Любая помощь была бы очень признательна

Комментарии:

1.Возможно, эти ресурсы могли бы помочь: aerogear.org/docs/guides/aerogear-android/authz github.com/aerogear/aerogear-android-cookbook/tree/master /…

2. Спасибо Вам, я просмотрел оба ресурса. На самом деле, код, который я представил, основан на второй ссылке, которую вы отправили, но я все еще не смог решить свою проблему. В любом случае спасибо 🙂

3. Пожалуйста. Не могли бы вы, пожалуйста, предоставить некоторую информацию о том, вызывается ли обратный вызов сбоя? Правильно ли настроен ваш Android-манифест? Кроме того, я полагаю, что вы не используете базовый URL-адрес 127.0.0.1 в своем клиенте Android, верно?

Ответ №1:

Если вы используете стандартный Authorization Code поток с типом доступа = public client (без clientSecret), вы можете взглянуть на мой пример родного приложения для Android.

Короче говоря, вы можете открыть окно браузера в a WebView , получить authorization code , проанализировав параметр запроса из возвращаемого URL-адреса, и обменять его (код) на токен с помощью POST-запроса.

Если вы используете Retrofit, то вот интерфейс REST:

 interface IKeycloakRest {
    @POST("token")
    @FormUrlEncoded
    fun grantNewAccessToken(
        @Field("code")         code: String,
        @Field("client_id")    clientId: String,
        @Field("redirect_uri") uri: String,
        @Field("grant_type")   grantType: String = "authorization_code"
    ): Observable<KeycloakToken>

    @POST("token")
    @FormUrlEncoded
    fun refreshAccessToken(
        @Field("refresh_token") refreshToken: String,
        @Field("client_id")     clientId: String,
        @Field("grant_type")    grantType: String = "refresh_token"
    ): Observable<KeycloakToken>

    @POST("logout")
    @FormUrlEncoded
    fun logout(
        @Field("client_id")     clientId: String,
        @Field("refresh_token") refreshToken: String
    ): Completable
}

data class KeycloakToken(
    @SerializedName("access_token")       var accessToken: String? = null,
    @SerializedName("expires_in")         var expiresIn: Int? = null,
    @SerializedName("refresh_expires_in") var refreshExpiresIn: Int? = null,
    @SerializedName("refresh_token")      var refreshToken: String? = null
)
  

И его создание:

 val rest: IKeycloakRest = Retrofit.Builder()
            .baseUrl("https://[KEYCLOAK-URL]/auth/realms/[REALM]/protocol/openid-connect/")
            .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()
            .create(IKeycloakRest::class.java)
  

Комментарии:

1. как добавить идентификатор устройства в код авторизации для добавления в заявку jwt?

Ответ №2:

Я тоже использую AeroGear, и я заметил, что у меня была та же проблема. Затем я сделал (помимо другой информации о конфигурации, как сказал Толис Эммануилидис) добавление службы аутентификации в ваш манифест.

Попробуйте добавить <service android:name="org.jboss.aerogear.android.authorization.oauth2.OAuth2AuthzService"/> в свой манифест

Как только вы это сделаете, он заработает должным образом, и вы сможете получить токен на предъявителя.

Ответ №3:

я реализовал это в своем проекте внутри моего класса keycloakHelper.

 public class KeycloakHelper {

static
{
    try
    {
        AuthorizationManager
                .config("KeyCloakAuthz", OAuth2AuthorizationConfiguration.class)
                .setBaseURL(new URL(EndPoints.HTTP.AUTH_BASE_URL))
                .setAuthzEndpoint("/auth/realms/***/protocol/openid-connect/auth")
                .setAccessTokenEndpoint("/auth/realms/ujuzy/protocol/openid-connect/token")
                .setRefreshEndpoint("/auth/realms/***/protocol/openid-connect/token")
                .setAccountId("account")
                .setClientId("account")
                .setRedirectURL("your base url")
                .addAdditionalAuthorizationParam((Pair.create("grant_type", "password")))
                .asModule();

        PipeManager.config("kc-upload", RestfulPipeConfiguration.class)
                .module(AuthorizationManager.getModule("KeyCloakAuthz"))
                .requestBuilder(new MultipartRequestBuilder());

    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

public static void connect(final Activity activity, final Callback callback)
 {
    if (!DetectConnection.checkInternetConnection(activity))
        return;

    try {
        final AuthzModule authzModule = AuthorizationManager.getModule("KeyCloakAuthz");
        authzModule.requestAccess(activity, new Callback<String>()
        {
            @SuppressWarnings("unchecked")
            @Override
            public void onSuccess(String s)
            {
                callback.onSuccess(s);
            }

            @Override
            public void onFailure(Exception e)
            {
               // authzModule.refreshAccess();
                authzModule.isAuthorized();
                if (!e.getMessage().matches(OAuthWebViewDialog.OAuthReceiver.DISMISS_ERROR))
                {
                    //authzModule.refreshAccess();
                    authzModule.deleteAccount();
                }
                callback.onFailure(e);

            }
        });

    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

public static boolean isConnected()
{
    return AuthorizationManager.getModule("KeyCloakAuthz").isAuthorized();
}
  

}

Когда вы хотите, чтобы пользователь вошел в систему (введите адрес электронной почты и пароль)

 public void LoginUser() {
    KeycloakHelper.connect(getActivity(), new Callback() {
        @Override
        public void onSuccess(Object o) {
            //YOU WILL GET YOUR TOKEN HERE IF USER IS ALREADY SIGNED IN. 
            //IF USER IS NOT SIGNED IN, AEROGEAR WILL PROMPT A WEBVIEW DIALOG
            //WHERE THE USER WILL INPUT THERE EMAIL AND PASSWORD
        }

        @Override
        public void onFailure(Exception e) {
                               
        }
    });
}
  

Счастливого кодирования 🙂