본문으로 건너뛰기

Application

소개

이 문서는 Unity, C#을 사용하여 PASSPORT 로그인을 구현하는 방법을 안내합니다.

소스코드

Workflow

Step 1. 맥스버스 앱 및 외부 브라우저 요청

  1. 모바일앱에서 맥스버스앱 및 외부브라우저(Chrome, Safari 등등)를 활용하여 로그인을 요청하고, 윈도우 또는 맥 에서는 외부브라우저(Chrome, Safari 등등)를 활용하여 로그인을 요청합니다.
  2. 로그인 요청시 성공할 경우 인가코드가 Redirect URI 로 전달됩니다.

Step 2. 로그인

패스포트에서 제공되는 PassportConfig 클래스를 상속받는 앱 인증 class 를 구성하고, 패스포트 기능 이용에 필요한 값들을 정의합니다. 아래 코드는 구성 예시 입니다.

public class SampleConfig : PassportConfig
{
public override ClientType clientType => ClientType.Public;

public override string Realm => "maxst";

public override string ApplicationId => "";

public override string ApplicationKey => "";

public override string GrantType => "client_credentials";

private static SampleConfig instance;
public static SampleConfig Instance
{
get
{
if (instance == null)
{
instance = new SampleConfig();

}
return instance;
}
}
}
변수타입설명
clientTypeClientType로그인시 사용, Public or Confidential
Realmstring사용되지 않음
ApplicationIdstringmaxverse console 애플리케이션 ID
ApplicationKeystringmaxverse console 애플리케이션 Key
GrantTypestring클라이언트 토큰 발급시 사용, client_credentials 고정

Public 클라이언트 타입

Public 클라이언트 타입의 로그인 방식은 OAuth2.0 PKCE(authorization code flow with proof key for code exchange)방식 입니다. 서비스 로그인 시퀀스 과정처럼 인가코드 요청, 토큰 요청 2단계로 로그인이 진행됩니다.

""

  1. unipassport를 활용하여 외부브라우저로 로그인화면을 호출합니다.
  2. Redirect URI 로 인가코드를 전달받은 모바일앱 에서 발급받은 인가 코드를 통해 토큰 발급을 요청합니다.
  3. PASSPORT 인증 서버는 토큰을 발급해서 토큰 정보를 응답합니다.
  4. 토큰발급 성공시 등록한 인터페이스로 토큰값을 전달받게 됩니다.

Confidential 클라이언트 타입

Confidential 클라이언트 타입은 일반적인 모바일 앱 등에서는 권장되지 않습니다.

해당 관련 내용은 설정페이지 에서 확인 가능합니다.

사전 설정

모바일(Android)에 Redirect URI 입력 및 Queries입력

Assets/Plugins/Android/AndroidManifest.xml 파일을 위치 하도록 하고, 아래와 같이 queries 및 Redirect URI 에 값을 전달할 Custom URL Scheme 값을 등록합니다.

<queries>
<package android:name="com.maxst.maxverse" />
</queries>

<application
android:extractNativeLibs="true"
android:hardwareAccelerated="true"
android:usesCleartextTraffic="true">
<activity
android:name="com.unity3d.player.UnityPlayerActivity"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"
android:hardwareAccelerated="true"
android:launchMode="singleTask"
android:resizeableActivity="false"
android:screenOrientation="reverseLandscape"
android:theme="@style/UnityThemeSelector">

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host=" oauth2redirect"
android:scheme="com.company.sample" />

</intent-filter>

</activity>
주의

⚠️ scheme 지정시 항상 소문자를 사용하여 지정해야 합니다.

모바일(iOS)에 Redirect URI 입력

Unity ProjectSetting 에서 iOS설정 선택후 Configuration 항목에서 Supported URL Schemes 부분에 값을 등록합니다.

&quot;&quot;

Editor(Window)에 Redirect URI 입력

Editor 의 경우 자체적으로 호출된 로컬 경로로 인가코드가 리턴되기 때문에 Redirect URI 값을 http://127.0.0.1:*/ 과 같이 등록해 주면 됩니다.

콘솔 등록 예시

  • Editor : http://127.0.0.1:*/

  • Android, iOS : com.company.sample://oauth2redirect 또는 com.company.sample://* 과 같이 본인이 앱에 설정한 값을 등록 합니다.

    &quot;&quot;

이해하기

시작하기

Step 1. 프로젝트 구성

  1. 본인 프로젝트의 Assets폴더 하위 경로에 소스코드를 다운로드 받아 위치 하도록 합니다.

    git clone https://github.com/maxstdev/unipassport.git

    &quot;&quot;

  2. Unirx 라이브러리를 추가합니다.

    GitHub Unirx
  • manifest.xml
    {
    "dependencies": {
    "com.neuecc.unirx": "https://github.com/neuecc/UniRx.git?path=Assets/Plugins/UniRx/Scripts",
    ...
    }
    }

Step 2. Scene 구성 및 동작 방법

로그인

  1. 외부브라우저 로그인페이지를 요청할 Scene에서 아래의 SampleScript.cs처럼 작성하고 이미지 처럼 구성합니다.

    &quot;&quot;

  • SampleCode(SampleScript.cs 예시)

    public class SampleScript : MonoBehaviour, IOpenIDConnectListener
    {
    [SerializeField] private OpenIDConnectArguments openidConnectArguments;
    private OpenIDConnectAdapter OpenIdConnectAdapter;
    public ILoginListener LoginListener { get; set; } = null;

    private void Awake()
    {
    OnInitialize();
    }

    public void OnFail(LoginErrorCode LoginErrorCode)
    {
    }

    public void OnLogout()
    {
    }

    public void OnSuccess(Token Token)
    {
    }
    }
  1. 아래 이미지를 참고하여 ScriptableObject의 값을 설정합니다.
  • OpenIDConnectArguments

    &quot;&quot;

  1. OAuth2.0 PKCE 방식에서 필요한 code_verifier, code_challenge 값은 로그인화면 호출 및 토큰요청시 필요하기 때문에 로그인화면 호출전 미리 생성하도록 합니다.

    내부 PKCEManager클래스의 GetCodeVerifier(), GetCodeChallenge(string CodeVerifier) 함수를 이용하여 생성하거나 직접 구현하여 code_verifier, code_challenge 값을 생성합니다.

  • SampleCode (PKCEManager 사용)

    var PKCEManagerInstance = PKCEManager.GetInstance();
    var CodeVerifier = PKCEManagerInstance.GetCodeVerifier();
    var CodeChallenge = PKCEManagerInstance.GetCodeChallenge(CodeVerifier);
  1. 이벤트 발생시(버튼클릭등) 아래의 소스코드를 호출하여 외부브라우저를 활용한 로그인화면을 호출하도록 합니다.
  • SampleCode

    OpenIdConnectAdapter.ShowOIDCProtocolLoginPage(CodeVerifier, CodeChallenge);
  1. 로그인 성공시 별도의 소스코드 추가 작업 없이 발급된 인가코드가 RedirectURI로 전달되고 해당값으로 토큰요청하며, 토큰발급이 완료된 경우 등록된 인터페이스로 해당 토큰값이 전달됩니다.
  • SampleCode

    public class SampleScript : MonoBehaviour, IOpenIDConnectListener
    {
    public ILoginListener LoginListener { get; set; } = null;

    [SerializeField] private OpenIDConnectArguments openidConnectArguments;

    public void OnSuccess(Token Token)
    {
    LoginListener?.OnSuccess();
    }

    public void OnFail(LoginErrorCode LoginErrorCode)
    {
    LoginListener?.OnFail(LoginErrorCode);
    }

    public void OnLogout()
    {

    }
    }

토큰 만료시간

발급받은 Token에 대하여 장시간 갱신이 없을경우(RefreshToken 제한 시간 이상 API 호출을 하지 않는 경우등등)에 대하여 어플리케이션 구조에 맞도록 자체적으로 개발하여 처리를 해야 합니다. 아래는 해당관련 처리 예제입니다. 토큰 만료시간 관련내용은 PASSPORT 로그인 이해하기에서 확인할수 있습니다.

  • SampleCode

    #if MAXST_TOKEN_AUTO_REFRESH
    StartRefreshTokenCoroutine();
    #endif
    ...

    private void StartRefreshTokenCoroutine()
    {
    StopRefreshTokenCoroutine();
    refreshTokenCoroutine = StartCoroutine(RefreshTokenRoutine());
    }

    ...
    private IEnumerator RefreshTokenRoutine()
    {
    while (true)
    {
    if (IsTokenExpired())
    {
    yield return FetchPassportRefreshToken(ClientID, GrantType, RefreshToken
    , e =>
    {

    });
    if (tokenStatus.Value != TokenStatus.Validate)
    {
    yield return new WaitForSeconds(5);
    }
    }
    else
    {
    var time = MeasureRemainTimeSeconds();
    yield return new WaitForSeconds(System.Math.Max(time / 2, 5));
    }
    }
    }

토큰 갱신하기

OpenIdConnectAdapter 의 OnRefreshToken() 호출시 토큰 갱신하기 REST API 형식에 맞게 토큰 갱신 요청을 하고 성공시 등록한 인터페이스의 OnSuccess(Token Token) 함수를 호출합니다.

  • SampleCode

    OpenIdConnectAdapter.OnRefreshToken();

로그아웃

  1. OpenIdConnectAdapter 의 OnLogout() 호출시 로그아웃 REST API 형식에 맞게 로그아웃 요청을 하고 성공시 등록한 인터페이스의 OnLogout() 함수를 호출합니다.
  • SampleCode

    OpenIdConnectAdapter.OnLogout();

클라이언트 토큰 발급

로그인 되지 않은 상태에서 api 를 사용해야 할 경우 애플리케이션 ID, 애플리케이션 Key 값을 등록하여 클라이언트 토큰을 발급받을수 있습니다. 해당토큰은 api 이용에 제약이 있을수 있습니다.

  • SampleCode
    var passportConfig = SampleConfig.Instance;
    OpenIdConnectAdapter.OnClientToken(passportConfig);

Step 3. 빌드옵션

  1. Window ,Mac ,Android, iOS 를 제공합니다.

    &quot;&quot;

  2. 위와같이 설정후 외부브라우저를 활용한 로그인화면을 호출하여 로그인을 진행하면 됩니다.

Step 4. 실행 동작 과정

  1. 첨부된 프로젝트의 Login Scene을 실행하여 확인 가능합니다.

    &quot;&quot;

  2. 이메일로 로그인하기 버튼을 클릭하여 외부브라우저 활용한 로그인화면으로 이동합니다.

    &quot;&quot;

    &quot;&quot;

  3. 웹 로그인 성공시 아래와같은 화면이 나오고, 해당 앱으로 Token 값이 전달됩니다.

    &quot;&quot;

    &quot;&quot;

OpenIDConnectAdapter.class

public void InitOpenIDConnectAdapter(OpenIDConnectArguments openidArguments, PassportConfig passportConfig = null)

OpenIDConnectAdapter를 이용하여 기능을 활용하려고 할경우, 해당 함수를 호출하여 설정한 값들이 등록되어야 합니다.

매개변수타입설명
openidArgumentsOpenIDConnectArguments패스포트 로그인시 필요한 설정 SO
passportConfigPassportConfig패스포트 이용시 필요한 설정 클래스

public void SetWindowLoginServiceManger(object provider)

UNITY_EDITOR 또는 UNITY_STANDALONE일 경우 유저로그인을 이용한다면 반드시 등록되어야 합니다.

매개변수타입설명
providerobject외부브라우저 로그인 성공하여 인가코드 반환받기 위해 등록

public void OpenUrlLoginPage(PassportConfig config)

로그인 페이지로 이동하고, 로그인 하게되면 토큰을 발급받게 됩니다.

매개변수타입설명
passportConfigPassportConfig패스포트 이용시 필요한 설정 클래스

public void OnRefreshToken(Action completeAction = null)

로그인하여 발급받은 토큰중 RefreshToken을 반환 받습니다.

매개변수타입설명
completeActionAction토큰 반환 받을 Action

public void OnLogout(Action completeAction = null)

로그아웃을 요청합니다. 로그인하여 발급받은 토큰은 사용할수 없게 됩니다.

매개변수타입설명
completeActionAction로그아웃 성공시 반환 받을 Action

public void OnClientToken(PassportConfig config, Action<TokenStatus, ClientToken> success = null,Action<ErrorCode, Exception> fail = null)

등록된 애플리케이션 ID, 애플리케이션 Key 정보로 클라이언트 토큰을 요청합니다. 해당토큰에는 API 제약이 있을수 있습니다.

매개변수타입설명
passportConfigPassportConfig패스포트 이용시 필요한 설정 클래스
successAction<TokenStatus, ClientToken>토큰 발급 성공시 상태값과 토큰 객체를 전달받을 Action
failAction<ErrorCode, Exception>토큰 발급 실패시 에러코드와 예외 객체를 전달받을 Action

TokenRepo.class

public Token GetToken()

로그인시 발급받은 토큰 객체를 반환합니다. 해당 토큰의 만료시간은 체크되어 반환되지 않습니다. 항상 유효한 토큰만 Get 해야 한다면 별도의 로직을 구현하여 사용되어야 합니다.

public ClientToken GetClientToken()

애플리케이션 ID, 애플리케이션 Key를 이용하여 발급받은 토큰 객체를 반환합니다. 해당 토큰의 만료시간은 체크되어 반환되지 않습니다. 항상 유효한 토큰만 Get 해야 한다면 별도의 로직을 구현하여 사용되어야 합니다.

public TokenDictionary GetClinetTokenDictionary()

애플리케이션 ID, 애플리케이션 Key를 이용하여 발급받은 토큰을 Dictionary 형태로 제공하여 반환합니다. 해당 토큰의 만료시간은 체크되어 반환되지 않습니다.

  TokenRepo.Instance.GetClinetTokenDictionary().GetTypedValue<T>(JwtTokenConstants.key);

형태로 토큰의 값을 반환하여 사용 가능합니다.