본문 바로가기

Project/Project_OurWorldCup

[Project/OurWorldcup] 로그인 OAuth2 + JWT - #1 도메인 추가 및 수정

반응형

본 프로젝트에서는 Spring Security 6 버전으로 OAuth2 + JWT를 사용하여 로그인 시스템을 구축하고자 합니다.

관련 링크:

들어가기 앞서, 오늘 구현한 도메인들의 형태는 대략 아래 그림과 같습니다.

대략적인 도메인 구성

그리고 아래 ERD는 오늘 설명과 관련된 테이블들의 구성입니다.

오늘 포스팅과 관련된 ERD

1. Authority 관련 도메인 추가

Authority란 "권한"을 의미합니다. 다양한 아티클에서 Role과 많이 혼동하고 있다고 이야기 합니다. 간단히 정리하자면,

  • Authority: "권한"자체를 의미합니다. 쓰기 권한 등이 있겠죠.
  • Role: "역할"을 의미합니다. 사용자 역할은, 쓰기 권한, 읽기 권한은 있지만, 삭제 권한은 없을 수 있습니다.
    즉 Role이란 여러 Authority를 포함하는 묶음 정도로 생각하면 됩니다.

사실 Authority는 Authentication(인증)된 유저에 한에서 Authorization(인가)할 때 사용되는 도메인이기 때문에, 인증 구현 이후에 작성하는 것이 좋다고 생각할 수 있지만, 경험상 도메인을 모두 수정한 후에 개발에 들어가는 것이 편합니다.

package com.example.ourworldcup.domain.auth;
... 생략
public class Authority implements GrantedAuthority {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    AuthorityType authorityType;


    @Override
    public String getAuthority() {
        return this.authorityType.getAuthority();
    }
}

해당 도메인은 AuthorityType을 필드로 가지고 잇습니다. AuthorityType enum 구조가 궁금하신 분은 위에 적혀있는 커밋을 통해 확인하시면 됩니다. 이후에도 언급되지 않았던 코드들은 모두 저 커밋에 들어있을 예정입니다.

GrantedAuthority (승인된 권한)정도로 해석하면 되며, 사용자가 가진 권한을 나타내는 데에 쓰입니다.

2. Role 관련 도메인 추가

위에서 설명한 바와 같이 Role은 여러 권한을 가집니다.

package com.example.ourworldcup.domain.auth;
.. 생략
public class Role {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    private RoleType roleType;
}

RoleType을 필드로 가집니다.

3. AuthProvider 도메인 수정

OAuth2 로그인을 할 때 로그인을 대신 해주는 Provider의 정보가 들어가 있습니다.

package com.example.ourworldcup.domain.auth;
... 생략
public class AuthProvider {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;

    @Enumerated(EnumType.STRING)
    private AuthProviderType authProviderType;
}

4. UserAccount 도메인 수정

사용자의 정보가 담기는 테이블 UserAccount에 로그인을 위한 필드들이 추가되어야 합니다.

package com.example.ourworldcup.domain.userAccount;
 ..생략
public class UserAccount extends AuditingFields {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
    @Column(nullable = false, length = 100) private String userId;
    @Column(nullable = false, length = 100) private String userName;
    @Column(length = 100) private String nickname;
    @Column(length = 100) private String email;

    @OneToMany(mappedBy = "userAccount", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @Builder.Default
    private List<UserAccountRole> userAccountRoles = new ArrayList<>();

    @ManyToOne(fetch = FetchType.EAGER)
    private AuthProvider authProvider;


    public UserAccount update(String userName) {
        this.userName = userName;
        return this;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserAccount that = (UserAccount) o;
        return email.equals(that.email) && authProvider == that.authProvider;
    }

    @Override
    public int hashCode() {
        return Objects.hash(email, authProvider);
    }
}

추가된 필드는 AuthProvider, userAccountRoles입니다. 나중에 엔티티의 동등성을 파악하는데 사용되는 equals()와 hashCode()함수를 위해 email과 authProvider를 사용할 것입니다. email, AuthProvider 조합은 유일성을 대표하기에 적절한 값들입니다. (카카오에서도 비슷하게 사용하고 있습니다.)

정리

일단 권한 관리를 위한 도메인 생성은 마무리 되었습니다. 다음 포스팅에선 OAuth 세팅을 진행할 예정입니다.

감사합니다.

반응형