j00r6 / SPYAIR-Fansite-Project

1 stars 1 forks source link

[BE] Docs : Oauth 2.0 From Issue #27 #73

Open j00r6 opened 7 months ago

j00r6 commented 7 months ago

27 이어지는 내용입니다.

구현 내용

Spring Security 와 Oauth 2.0 을 활용하여 소셜로그인 기능 구현


구현 방식

Oauth 를 통한 로그인 구현은 2가지 의존성이 있어서 햇갈렸다.

implementation 'org.springframework.security.oauth:spring-security-oauth2:2.5.2.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client:3.2.2'
  1. Spring Security 기반
  2. Spring Boot 기반

1번 의존성은 Security 5버전 이상부터는 사용되지 않는다고한다.


개념

Oauth의 개념은 단순하게 구글, 카카오, 네이버 의 서버에 이미 가입되어있는 유저정보를 내 서버로 가지고와서 가입이 된것처럼 인증처리를 진행하는 것으로 해석했다.

Oauth 관련 용어 설명을 보면 Resource Server 즉, 회원정보를 가지고있는 구글, 카카오, 네이버, 측을 기점으로 용어가 정립되어있다.

자사 서비스가 있고 소셜로그인을 구현한다면 백의 역할은 자사 서비스에서 JWT를 활용해 인증된 토큰을 발급했던 것처럼 소셜(구글, 카카오, 네이버 등등)에서 발급된 토큰을 받아 프론트측에 전달하는 용도로 활용된다.

그 과정에서 소셜로 로그인을 진행한 유저의 정보를 자사 서비스에 저장을 하고 싶다면 추가 구현이 필요하다.


구현

구현방식은 JWT를 구현할때와 비슷하다고 생각한다. JWT를 구현할때 UserDetails를 활용하여 내가 토큰에 추가하고 싶은 정보를 추가했었다.

DefaultOauth2User

Oauth를 구현할때에도 Resource Server 에 저장된 데이터중 내가 활용하고싶은 데이터만 골라서 가져올수 있으며 그중에 자사 서비스에서 활용되는 데이터를 추가할수도 있다.

@Getter
public class CustomOAuth2User extends DefaultOAuth2User {

    private String email;
    private Role role;

    /**
     * Constructs a {@code DefaultOAuth2User} using the provided parameters.
     *
     * @param authorities      the authorities granted to the user
     * @param attributes       the attributes about the user
     * @param nameAttributeKey the key used to access the user's "name" from
     *                         {@link #getAttributes()}
     */

    public CustomOAuth2User(Collection<? extends GrantedAuthority> authorities,
                            Map<String, Object> attributes, String nameAttributeKey,
                            String email, Role role) {
        super(authorities, attributes, nameAttributeKey);
        this.email = email;
        this.role = role;
    }
}

위 코드에서는 자사 서비스에서 활용되는 email role 을 추가 한것을 볼수있다.

사용자 동의시 제공 항목

네이버와 카카오로 소셜로그인을 진행할 시 사용자 정보 제공 동의항목 을 본적이 있을것이다. 위에 내용에서 연결되는 내용으로 아래 제공 항목중 원하는 항목을 추가하여 활용할수 있다.

네이버

{
  "resultcode": "00",
  "message": "success",
  "response": {
    "email": "openapi@naver.com",
    "nickname": "OpenAPI",
    "profile_image": "https://ssl.pstatic.net/static/pwe/address/nodata_33x33.gif",
    "age": "40-49",
    "gender": "F",
    "id": "32742776",
    "name": "오픈 API",
    "birthday": "10-01"
  }
}

카카오

{
    "id":123456789,
    "connected_at": "2022-04-11T01:45:28Z",
    "kakao_account": { 
        // 프로필 또는 닉네임 동의 항목 필요
        "profile_nickname_needs_agreement": false,
        // 프로필 또는 프로필 사진 동의 항목 필요
        "profile_image_needs_agreement  ": false,
        "profile": {
            // 프로필 또는 닉네임 동의 항목 필요
            "nickname": "홍길동",
            // 프로필 또는 프로필 사진 동의 항목 필요
            "thumbnail_image_url": "http://yyy.kakao.com/.../img_110x110.jpg",
            "profile_image_url": "http://yyy.kakao.com/dn/.../img_640x640.jpg",
            "is_default_image":false
        },
        // 이름 동의 항목 필요
        "name_needs_agreement":false, 
        "name":"홍길동",
        // 카카오계정(이메일) 동의 항목 필요
        "email_needs_agreement":false, 
        "is_email_valid": true,   
        "is_email_verified": true,
        "email": "sample@sample.com",
        // 연령대 동의 항목 필요
        "age_range_needs_agreement":false,
        "age_range":"20~29",
        // 출생 연도 동의 항목 필요
        "birthyear_needs_agreement": false,
        "birthyear": "2002",
        // 생일 동의 항목 필요
        "birthday_needs_agreement":false,
        "birthday":"1130",
        "birthday_type":"SOLAR",
        // 성별 동의 항목 필요
        "gender_needs_agreement":false,
        "gender":"female",
        // 카카오계정(전화번호) 동의 항목 필요
        "phone_number_needs_agreement": false,
        "phone_number": "+82 010-1234-5678",   
        // CI(연계정보) 동의 항목 필요
        "ci_needs_agreement": false,
        "ci": "${CI}",
        "ci_authenticated_at": "2019-03-11T11:25:22Z",
    },
    "properties":{
        "${CUSTOM_PROPERTY_KEY}": "${CUSTOM_PROPERTY_VALUE}",
        ...
    }
}

정보 가져오기

public abstract class OAuth2UserInfo {

    protected Map<String, Object> attributes;

    public OAuth2UserInfo(Map<String, Object> attributes) {
        this.attributes = attributes;
    }

    public abstract String getId(); //소셜 식별 값 : 구글 - "sub", 카카오 - "id", 네이버 - "id"

    public abstract String getNickname();

    public abstract String getImageUrl();
}

Oauth 서비스 로직

이외에 서비스 로직은 자사가 제공하는 서비스에 맞게 혹은 구현하고자 하는 도메인에 맞게 로직을 구성하면 된다.

Ref

참조 1 - 공식문서 참조 2 - 공식문서 참조 3 - 블로그 참조 4 - 블로그