Future Social Authentication Improvements… 이어서
현재 모든 ‘연결된 계정’ 정보를 단일 데이터베이스 테이블로 이동하는 작업을 진행 중입니다. 이를 통해 중복 로직을 크게 줄이고, 향후 개발 속도를 높일 수 있습니다. 예를 들어, 핵심 트위터 로직을 새로운 시스템으로 마이그레이션한 결과, 코드 라인 수가 136줄에서 단 24줄로 줄었습니다
.
이 게시글은 새로운 인증 제공자를 추가하는 단계별 매뉴얼을 목표로 하지 않지만, 필요한 경우 관련 소스 코드를 가리키며 개요를 제공하고자 합니다.
인증기(Authenticator) 구현
각 인증기는 Auth::Authenticator의 하위 클래스를 구현해야 합니다. 새로운 공유 로직을 사용하려면, 인증기는 대신 Auth::ManagedAuthenticator를 확장할 수 있습니다. 최소한의 구현 예제는 핵심 Facebook 인증기에서 찾을 수 있습니다:
name과 register_middleware는 구현 클래스에서 오버라이드되어야 하며, 관리자/provider를 켜기 위해 사용하는 불리언 사이트 설정인 enable_setting도 포함됩니다.
인증기는 required_settings를 선언하는 것이 좋습니다. 이는 인증이 성공하기 전에 값이 있어야 하는 사이트 설정입니다. 베이스 클래스는 configured?에 이를 사용하며, enabled?는 enable_setting && configured?이므로 자격 증명이 누락된 제공자는 로그인 페이지에 노출되지 않고 해당 /auth/<name> 라우트는 닫힌 상태를 유지합니다. 그렇지 않으면 버튼을 클릭한 사용자가 제공자 자체의 오류 페이지에 갇혀 돌아올 수 없게 됩니다. required_settings를 선언하면 AuthProviderCredentialsValidator가 제공자를 활성화하는 것을 처음부터 거부할 수 있으며, 활성화 설정에 validator: "AuthProviderCredentialsValidator"를 연결하여 이를 설정합니다.
def enable_setting
:enable_google_oauth2_logins
end
def required_settings
%i[google_oauth2_client_id google_oauth2_client_secret]
end
enabled?를 직접 오버라이드하는 인증기는 두 가지 게이트(조건) 모두에서 제외됩니다.
참고: 멀티사이트 호환성을 위해 사이트별 정보는 정의 시점에 고정되는 것이 아니라
setup람다를 통해 omniauth에 제공되는 것이 중요합니다. 이에 대한 예제는 모든 핵심 인증기를 참고하십시오.
외부 계정을 Discourse 계정에 연결하는 모든 로직은 Auth::ManagedAuthenticator가 처리합니다. 이는 omniauth 제공자가 그들의 문서에서 정의된 형식으로 데이터를 반환하는 데 의존합니다. 이 데이터의 조작이 필요하면, 인증기는 after_authenticate 메서드를 오버라이드하여 auth_token을 필요에 따라 조작할 수 있습니다. 예를 들어, 핵심 Twitter 인증기는 토큰에서 모든 extra 정보를 제거합니다:
데이터는 user_associated_accounts 데이터베이스 테이블에 저장됩니다. provider_uid, info, credentials 및 extra는 모두 omniauth가 반환한 데이터에서 직접 가져옵니다.
프로바이더 이미지는 인증 시 info.image에서 다운로드되어 각 계정의 avatar_upload_id에 보관됩니다. 이는 사용자의 업로드된 사진 및 선택 가능한 프리셋과 별도로 유지됩니다. 아바타 선택기는 기존 아바타 권한 하에서 활성화된 프로바이더의 캐시된 이미지를 제공합니다.
UserAvatar는 아바타 가져오기, 선택, 새로 고침 및 정리 작업을 담당합니다. 인증은 UserAvatar.retrieve_for_associated_account를 통해 프로바이더 검색을 예약하며, 다운로드 작업 및 가져오기는 프로바이더 이미지의 경우 associated_account_id를 전달하여 UserAvatar.import_url_for_user를 사용합니다. 사용자 편의 메서드 및 계정/업로드 라이프사이클 콜백은 아바타 변경을 UserAvatar에 위임하며, 권한은 Guardian에 남아 있습니다.
user_avatars.selected_user_associated_account_id는 명시적으로 선택된 프로바이더를 기록합니다. 해당 프로바이더가 선택된 상태인 동안에만 후속 다운로드가 표시되는 아바타를 업데이트합니다. 아바타가 할당되지 않은 경우 새 계정은 초기에 프로바이더를 선택하며, auth_overrides_avatar는 프로바이더 선택을 계속 강제합니다. 기존 아바타는 외관을 유지하며 프로바이더가 자동으로 할당되지 않습니다. 기존 연결된 계정은 다음 로그인 시 프로바이더 선택을 채웁니다.
다른 아바타를 선택하면 프로바이더 선택이 해제됩니다. 계정을 연결 해제하면 현재 표시 중인 이미지를 로컬 스냅샷으로 유지하고, 별도로 업로드된 사진도 유지합니다. 다운로드 실패 시 이전 이미지를 유지합니다. 계정이 연결 해제되었거나, 다른 사용자로 이동했거나, 이제 다른 이미지 URL을 제공하는 경우 대기 중인 다운로드는 폐기됩니다.
Gravatar 선택은 여전히 업로드-ID 매칭을 사용합니다. 따라서 캐시된 Gravatar와 동일한 사용자 지정 또는 프리셋 사진은 후속 Gravatar 업데이트를 따라갈 수 있습니다.
Authenticator 클래스가 정의되면 등록이 필요합니다. 이는 애플리케이션 라이프사이클의 초기에 이루어져야 하며, 플러그인의 after_initialize 메서드 내에서 수행할 수 없습니다. 최소한의 등록은 인증기에 대한 참조만 포함하면 됩니다. 플러그인에서는 auth_provider 함수를 사용하여 등록할 수 있습니다. 예를 들어:
auth_provider authenticator: OpenIDConnectAuthenticator.new()
코어에서는 등록이 discourse.rb에서 이루어집니다. 가능한 AuthProvider 옵션의 전체 목록은 여기에서 찾을 수 있습니다. 텍스트 콘텐츠는 이러한 옵션을 사용하여 정의할 수 있지만, 표준 키를 따르면서 client.en.yml에서 로컬라이즈 가능한 문자열을 제공하는 것이 더 좋습니다. 예를 들어:
@fantasticfears의 추가 ManagedAuthenticator 노트
ManagedAuthenticator 상세 정보
인증과 관련하여 특별한 작업을 수행해야 할 수 있습니다. 그리고 ManagedAuthenticator에 대해 더 알고 싶을 것입니다. 기본적으로 여러 작업, 옵션을 가지고 있으며 데이터가 어떻게 사용될지 제어합니다.
Discourse는 두 개의 컨트롤러를 통해 사용자 정보를 관리합니다. Users::OmniauthCallbacksController는 OAuth2 인증이 완료된 후 페이로드를 관리합니다. after_authenticate가 여기서 호출됩니다. can_connect_existing_user?도 여기서 사용됩니다.
서로 다른 데이터 필드가 어떻게 작동하는지 이해하기 위해 읽을 수 있는 일부 비공개 메서드가 있습니다.
if authenticator.can_connect_existing_user? && current_user
@auth_result = authenticator.after_authenticate(auth, existing_account: current_user)
else
@auth_result = authenticator.after_authenticate(auth)
end
UsersController에는 can_revoke?와 revoke를 사용하는 revoke_account가 있습니다. 하지만 revoke 메서드가 원격으로 작동하려면 자체 구현을 구축해야 합니다.
UserAuthenticator는 사용자를 인증(이메일 확인 또는 OAuth2 경로)하는 데 도움을 주는 서비스 클래스입니다. after_create_account가 여기서 호출됩니다.
핵심 로직은 Auth::Result 데이터 클래스와 함께 after_authenticate에 남아 있습니다. 여기서 데이터 구조를 따릅니다. extra_data는 관련 레코드를 생성하기 위해 after_create_account에 전달됩니다.
result.extra_data = {
provider: auth_token[:provider],
uid: auth_token[:uid],
info: auth_token[:info],
extra: auth_token[:extra],
credentials: auth_token[:credentials]
}
기존 계정과 매칭하여 연결을 시도합니다.
자동 계정 생성은 가능하지만 왜 User.create가 없는지 궁금할 수 있습니다. 이는 UsersController#create에서 수행됩니다.
authentication = UserAuthenticator.new(user, session)
user는 새로운 인스턴스이며, 인증 제공자가 준비한 세션 데이터로 채워집니다. 믿어주세요, 이건 그냥 마법입니다.
새 시스템으로의 마이그레이션
새 시스템으로의 원활한 전환을 제공하기 위해, 데이터는旧的 저장 위치에서 마이그레이션되어야 합니다. 핵심 인증 제공자의 경우, 이는 전용 테이블일 수 있습니다. 플러그인의 경우, 이는 plugin_store_rows 또는 oauth2_user_infos일 수 있습니다. user_associated_accounts 행에 필요한 최소 데이터는 provider_name, provider_uid 및 user_id입니다. 마이그레이션 예제는 다음을 참고하십시오:
ManagedAuthenticator 시스템이 v2.2.0과 함께 안정 버전 브랜치에 릴리스되면, 공식 인증 플러그인의 마이그레이션을 시작할 것입니다. 이 시점에서 plugin_store_row 마이그레이션 예제가 여기에 추가될 것입니다.
이 문서는 버전 관리됩니다 - 변경 사항을 github에서 제안하십시오.