솜은 코튼

[Android] Microsoft MSAL 적용 방법 본문

Android/Java

[Android] Microsoft MSAL 적용 방법

솜.코 2021. 1. 7. 15:18

[참고 사이트 주소]

github.com/AzureAD/microsoft-authentication-library-for-android

 

AzureAD/microsoft-authentication-library-for-android

Microsoft Authentication Library (MSAL) for Android - AzureAD/microsoft-authentication-library-for-android

github.com

 

소스 구현 방법

    1. build.gradle 
       

    1-1

    1-2. 


    2. Azure 관리자 페이지
       :해당 SDK를 사용하려면 Azure 관리자 페이지에 프로젝트 등록을 해주어야 합니다.

        (아래 주소로 접속하여 로그인 진행 후 절차대로 진행하세요.)

 

[사이트 주소]

aka.ms/AppRegistrations

 

Microsoft Azure

 

portal.azure.com

 

    2-1. 로그인 진행 후 앱 등록 페이지가 뜨면 새등록 클릭

 

    2-2. 애플리케이션 정보 등록
       :'지원되는 계정 유형' 관련된 설명은 아래 사이트를 참고하세요.

docs.microsoft.com/en-us/azure/active-directory/develop/supported-accounts-validation

 

Validation differences by supported account types - Microsoft identity platform

Learn about the validation differences of various properties for different supported account types when registering your app with the Microsoft identity platform.

docs.microsoft.com

 

    2-3. 좌측 메뉴의 인증 > 플랫폼 추가

 

    2-4. 원하는 플랫폼 선택

 

    2-5. 패키지명과 해시값 등록 후 구성 클릭

 

  ※ 위의 과정을 완료하면 리디렉션 URI와 MSAL 구성 정보가 생성됩니다. 이 정보들은 개발하실 때 필요한 정보입니다.

 

    3. res > raw 폴더 안에 json 파일 생성
       :관리자 페이지에서 생성한 MSAL 구성 정보 기입

 

    4. AndroidManifest.xml


    4-1. 퍼미션 등록


    4-2. MSAL 로그인 페이지 등록

 

    5. MSAL 초기화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// auth_config_multiple_account.json을 사용하여 PublicClientApplication 개체 생성
PublicClientApplication.createMultipleAccountPublicClientApplication(context,
        R.raw.auth_config_multiple_account,
        new IPublicClientApplication.IMultipleAccountApplicationCreatedListener() {
            @Override
            public void onCreated(IMultipleAccountPublicClientApplication application) {
                mMultipleAccountApp = application;
                loadAccounts(method);
            }
 
            @Override
            public void onError(MsalException exception) {
                Log.d(LOG_TAG, exception.toString());
                loadUrl(method, null);
            }
        });
cs

 

    6. 대화형 또는 자동으로 토큰 가져오기(처음 로그인 시)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (mMultipleAccountApp == null) {
    return;
}
 
/**
 * acquireTokenSilent()가 상호 작용이 필요한 오류 (MsalUiRequiredException)를 반환하면,
 * 사용자가 인터랙티브하게 인터럽트를 해결하도록하려면 acquireToken()을 호출합니다.
 *
 * 몇 가지 예시 시나리오는 다음과 같습니다.
 *  - 비밀번호 변경
 *  - 토큰을 획득하는 리소스에는 Single Sign-On 새로 고침 토큰보다 더 엄격한 요구 사항이 있습니다.
 *  - 사용자가 동의하지 않은 새로운 범위를 도입
 */
mMultipleAccountApp.acquireToken((MainActivity)context, getScopes(scope), getAuthInteractiveCallback(method));
cs

 

    7. 대화형 또는 자동으로 토큰 가져오기 (사용자가 이미 로그인한 경우: 앱에서 사용자에게 메시지를 표시하지 않고 토큰을 요청)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if (mMultipleAccountApp == null) {
    return;
}
 
IAccount selectedAccount = null;
try {
    selectedAccount = mMultipleAccountApp.getAccount(id);
catch (InterruptedException e) {
    e.printStackTrace();
catch (MsalException e) {
    e.printStackTrace();
}
 
/**
 * 사용자를 방해하지 않고 acquireToken을 수행
 *
 * 이를 위해서는 토큰을받는 계정의 계정 개체가 필요
 * (getAccount ()를 통해 얻을 수 있음).
 */
mMultipleAccountApp.acquireTokenSilentAsync(getScopes(scope),
        selectedAccount,
        selectedAccount.getAuthority(),
        getAuthSilentCallback(method));
cs

 

    8. 계졍 로드: 현재 로그인 된 계정이있는 경우 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (mMultipleAccountApp == null) {
    return;
}
 
mMultipleAccountApp.getAccounts(new IPublicClientApplication.LoadAccountsCallback() {
    @Override
    public void onTaskCompleted(final List<IAccount> result) {
        // 계정 데이터를 사용하여 UI 또는 앱 데이터베이스를 업데이트 할 수 있음
        accountList = result;
        loadUrl(method, getArrAccount());
    }
 
    @Override
    public void onError(MsalException exception) {
        Log.d(LOG_TAG, exception.toString());
        loadUrl(method, null);
    }
});
cs

 

    9. '대화형 또는 자동으로 토큰 가져오기(처음 로그인 시)' 후의 콜백

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
new AuthenticationCallback() {
 
    @Override
    public void onSuccess(IAuthenticationResult authenticationResult) {
        /* 액세스 토큰 획득 성공 */
        Log.d(LOG_TAG, "Successfully authenticated");
 
        /* call graph */
        callGraphAPI(method, authenticationResult);
 
        /* 최신 목록을 얻으려면 비동기 적으로 계정을 새로 고침 */
        // loadAccounts(method);
 
        /* MAM 계정 등록 */
        // MAMManager.getInstance(context).handleSignInSuccess(authenticationResult);
    }
 
    @Override
    public void onError(MsalException exception) {
        /* 액세스 토큰 획득 실패 */
        Log.d(LOG_TAG, "Authentication failed: " + exception.toString());
 
        if (exception instanceof MsalClientException) {
            /* MSAL 내부 예외 */
        } else if (exception instanceof MsalServiceException) {
            /* STS와 통신 할 때 예외 */
        }
        loadUrl(method, null);
    }
 
    @Override
    public void onCancel() {
        /* 사용자가 인증을 취소 */
        Log.d(LOG_TAG, "User cancelled login.");
        loadUrl(method, getArrAccount());
    }
};
cs

 

    10. '대화형 또는 자동으로 토큰 가져오기 (사용자가 이미 로그인한 경우)' 후의 콜백

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
new SilentAuthenticationCallback() {
 
    @Override
    public void onSuccess(IAuthenticationResult authenticationResult) {
        Log.d(LOG_TAG, "Successfully authenticated");
 
        /* 액세스 토큰 획득 성공 */
        /* call graph */
        callGraphAPI(method, authenticationResult);
 
        /* MAM 계정 등록 */
        // mamManager.handleSignInSuccess(authenticationResult);
    }
 
    @Override
    public void onError(MsalException exception) {
        /* 액세스 토큰 획득 실패 */
        Log.d(LOG_TAG, "Authentication failed: " + exception.toString());
 
        if (exception instanceof MsalClientException) {
            /* MSAL 내부 예외 */
        } else if (exception instanceof MsalServiceException) {
            /* STS와 통신 할 때 예외 */
        } else if (exception instanceof MsalUiRequiredException) {
            /* 토큰이 만료되었거나 세션이 없을 때 예외 */
        }
    }
};
cs

 

    11. MSGraph 데이터를 얻기 위해 HTTP 요청

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
MSGraphRequestWrapper.callGraphAPIUsingVolley(
context,
defaultGraphResourceUrl,
authenticationResult.getAccessToken(),
new Response.Listener<JSONObject>() {
    @Override
    public void onResponse(JSONObject response) {
        /* 성공적으로 그래프 호출, 데이터 처리 및 UI로 전송 */
        Log.d(LOG_TAG, "Response: " + response.toString());
        loadUrl(method, "SUCCESS", authenticationResult);
    }
},
new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        Log.d(LOG_TAG, "Error: " + error.toString());
        loadUrl(method, "FAIL", authenticationResult);
    }
});
cs

 

    12. 로그인 된 계정 정보

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
JSONArray arr = new JSONArray();
JSONObject obj = new JSONObject();
 
if(accountList==nullreturn arr;
 
for(IAccount account:accountList){
    try {
        obj.put("email", account.getUsername());
        obj.put("token", account.getIdToken());
        obj.put("id", account.getId());
    } catch (JSONException e) {
        e.printStackTrace();
    }
    arr.put(obj);
}
return arr;
cs

 

    13. 계정 제거

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if (mMultipleAccountApp == null) {
    return;
}
 
//이 앱 (또는 장치가 공유 모드 인 경우 장치)에서 선택한 계정과 캐시 된 토큰을 제거
try {
    mMultipleAccountApp.removeAccount(mMultipleAccountApp.getAccount(id),
            new IMultipleAccountPublicClientApplication.RemoveAccountCallback() {
                @Override
                public void onRemoved() {
                    Log.d(LOG_TAG, "Account removed.");
 
                    /* 최신 목록을 얻으려면 비동기적으로 계정을 다시 로드 */
                    loadAccounts(method);
                }
 
                @Override
                public void onError(@NonNull MsalException exception) {
                    Log.d(LOG_TAG, exception.toString());
                    loadUrl(method, null);
                }
            });
catch (InterruptedException e) {
    e.printStackTrace();
catch (MsalException e) {
    e.printStackTrace();
}
cs