Skip to content

Security Authentication

vks edited this page Jul 8, 2024 · 6 revisions

💭 문제 인식

기존 Security 없이 로그인과정을 구현했지만 Security의 필요성을 느껴 구현하던 도중 Authentication 과정에서 문제가 발생하였다.

Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException

원래대로라면,

회원로그인 → AuthService → UserDetailsService → JwtFilter Authorization → AccessToken, RefreshToken 응답

과정을 거쳐 Authentication/Authorization 과정이 이루어지는데 UserDetailsService에서 무슨 이유인지 NumberFormatException이 발생하였다.

🛠️ 문제 해결시도

📍첫 번째로, 로그를 확인해보았다.

로그를 확인해보니, User Class에서 Name을 String에서 Long Type으로 변경할 수 없다고 나와있었다.

📍두 번쨰로, 디버깅을 해보았다.

문제가 User Class에서 일어났으니, 해당 부분을 중단점을 찍어 디버깅해보았다.

Authentication 이 진행될 때, User Class에 들어가는 username 부분 값을 확인해보니, memberId가 아니라 email이 들어갔었다..

처음에는, memberId로 Authentication을 구현하려하였지만, 인증 후 인증이 필요한 API 호출에서 로그인한 회원의 정보를 쓰는 경우가 많으므로 CustomUserDetails Class로 만들어 사용해야할 필요성을 느꼈다..!

✅ 해결 방법

📝 CustomUserDetails 작성.

다른 클래스에서도 인증된 사용자에 대한 email, memberId, role, social 정보가 필요하기 때문에, CustomUser를 만들어 사용하였다. 아래는 해당 CustomUser 클래스이다..

🛠️ User를 상속받는 MemberDetails

  • 🟢 서버에서 authorization을 진행할 때 authentication이 필요한 API 요청들은 로그인중인 회원의 정보가 필요하므로, 로그인한 회원의 정보를 전부 사용할 수 있도록 구현하였다.
package com.devcv.auth.details;

import com.devcv.member.domain.Member;
import lombok.Getter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

@Getter
public class MemberDetails extends User {

    private final Member member;

    public MemberDetails(Member member, List<? extends GrantedAuthority> authorities) {
        super(member.getEmail(), member.getPassword(), authorities);
        this.member = member;
    }

    @Override
    public Collection<GrantedAuthority> getAuthorities() {
        return Collections.singleton(new SimpleGrantedAuthority("ROLE_"+(member.getMemberRole().name())));
    }

    @Override
    public String getPassword() {
        return member.getPassword();
    }

    @Override
    public String getUsername() {
        return String.valueOf(member.getMemberId());
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MemberDetails that = (MemberDetails) o;
        return Objects.equals(member, that.member);
    }

    @Override
    public int hashCode() {
        return Objects.hash(member);
    }

}