로그인 만들기

김태성·2024년 9월 10일

개인 프로젝트-1

목록 보기
38/53
post-thumbnail

이제 로그인을 만들 차례이다.
KEPCO 데이터가 완전하게 들어온 것을 확인했으니, 이를 바탕으로 로그인 기능을 만들어
유저에게 데이터를 전달할 수 있는 기능을 만들어 보자.

JWT, 세션 중 뭘쓸것인가

결론만 말하면 JWT를 사용할것이다.

세션과 JWT의 장/단점을 알아보자.

세션 장점

  • 서버에서 클라이언트의 로그아웃을 컨트롤 할 수 있음.
  • 세션 정보가 서버에 저장되어서 쿠키가 탈취되어도 보안상 위협이 적음

세션 단점

  • 확장성이 낮음. 유저가 늘어날수록 속도가 느려지는 방식
  • 속도 이슈로 Redis 사용이 반 강제되서 서버 인스턴스에 부하를 줄 수 있음.

JWT 장점

  • 간단하고 편리함. 쿠키 하나 구워서 클라이언트한테 전해주면 끝
  • 확장성이 좋음. 유저가 늘어나도 속도가 느려지진 않음
  • 무상태 인증 방식이다. 이전에 무엇을 했는지 서버가 알지 못한다.

JWT 단점

  • 쿠키가 유출되었을때 쿠키 만료시간까지 해커가 사용할 수 있음
  • 또한 쿠키에 데이터를 많이 담아야 함으로 탈취시 문제 발생할 가능성 생김

그럼 왜 JWT를 사용하나?

  • 서버가 많이 약하다. 확장을 한다면 모를까 지금 상황에서는 어떻게든 부하를 줄여야됨.
  • HTTPS 보안을 적용했기에 탈취의 위험에서 조금 자유로움.
  • 민감 데이터가 많이 없다. 기껏해봐야 유저의 지역정보인데, 정확한 집주소도 아니고 대략적
  • Redis의 러닝커브가 어떨지 모른다. 대충 사용하기 위해 억지로 끼워넣는건 안쓰는게 낫다고 판단.
  • 쿠키 만료시간을 짧게 잡아 JWT의 단점을 보완할 예정.

데이터를 받아오는 구간

레퍼런스 : https://darrenlog.tistory.com/40
한줄기의 빛과도 같은 글이다.
쌩으로 구현하려고 하니 머리가 아팠는데, 가이드 덕분에 부담을 덜었다.

코드를 작성하고 실행해 보자.

이전에 Security를 껐었는데, http 설정이 되지 않아서 오류가 발생한다.
지우고 다시 실행하니차단당했다. 뭔가 이상함을 느껴서 네트워크 탭에서 확인해보니
데이터는 잘 들어오고 있다...

http://localhost:8082/login/oauth2/code/google?code=4%2F0AQlE

위와 같은 데이터가 들어온다면, code의 값만 때로 parameter로 받아내야 하는데 참 이상하다.
그래서 영어 레퍼런스부터 코드까지 싹다 뜯어보면서 검색해 보니

implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'

dependency가 설정되어 있는것을 확인했다.
위 depencency를 지우고 확인하니

invalid_request를 7시간 본 뒤 드디어 해결했다.
나중에 security에 대해 공부해 보겠지만..

Security를 사용하면 위와 같은 화면이 계속 뜬다.
알지도 못하는 프레임워크 좋아보인다고 처음에 설정했던거 같다.(기억은없음)
Dependency 생각못했으면 며칠 걸리다가 코드를 밀어버릴수도 있다 생각하니
온몸에 소름이 돋는다.

위의 레퍼런스를 잘 따라가며

제네릭 타입을 명시해 준다.

데이터를 받아오는걸 성공했다!

백엔드 배포

Controller를 리팩토링 해줬다.

백엔드에 배포했을때 systemcall을 확인하지 못하기 때문에 return 값을 통해서 명시적으로 확인하기 위해서다.

Jenkins에서 배포할때 환경변수도 집어넣어주니

서버에도 잘 배포가 되는 모습

회원가입 기능 만들기

회원가입과 로그인 2가지 분류로 나눠야 한다.

회원가입

  • 유저 데이터를 DB에 저장하는것

로그인

  • 쿠키를 받아서 서버에 요청을 보낼때마다 토큰을 보낼 수 있는 상태로 만드는것
  • 따라서 서버가 로그인 완료될때 client에게 토큰을 줘야 한다.

쿠키의 확인은 프론트 페이지에서 담당할 것이다.
React에서 API 호출 코드에 쿠키 검사 로직을 집어넣고 쓰면 된다.
그리고 React Cookie라는 좋은 기능이 있어서 쓰기도 편하다.

먼저 프론트에서 백엔드의 데이터가 받아와 지는지 확인해 보자.

이처럼 단순하게 url을 이동하는 로직을 만들었고,

잘 된다. 하지만 json 형태로 데이터가 들어와서 사용하지를 못한다..
그래서 parameter를 받아오는 형태로 바꾸려고 했다.

처음에는 이렇게 response 값으로 하려고 했으나

The Unicode character [] at code point [44,608] cannot be encoded 
as it is outside the permitted range of 0 to 255

장렬하게 터져버렸고

인코딩을 해서 보내주기로 했다.

깔끔하게 잘 들어오는 모습.
이제 이걸 parameter로 받아서

route로 이어주고

function Signup() {
    const location = useLocation();
    const [user, setUser] = useState({ name: '', email: '' });

    useEffect(() => {
        // 파라미터 추출
        const params = new URLSearchParams(location.search);
        const name = params.get('name');
        const email = params.get('email');

        if (name && email) {
            // 디코딩
            setUser({
                name: decodeURIComponent(name),
                email: decodeURIComponent(email),
            });
        }
    }, [location]);

    const handleSubmit = () => {
        // 회원가입 처리 로직 추가 예정
        console.log('회원가입 완료:', user);
    };

    return (
        <div>
            <h1>회원가입</h1>
            <form onSubmit={handleSubmit}>
                <div>
                    <label>이름: {user.name}</label>
                </div>
                <div>
                    <label>이메일: {user.email}</label>
                </div>
                <button type="submit">회원가입</button>
            </form>
        </div>
    );
}

export default Signup;

간단하게 페이지 하나 만들어줬다.

데이터를 처리할 수 있게 되었다.

이제 유저의 데이터를 DB에 넣을 준비를 해야된다.

여기서 잠깐 이슈가 있었는데, class 이름을 user로 하면 오류가 난다.

테이블이 잘 만들어 졌다.
이제 OAuth에서 받은 정보를 바탕으로 가입되어있는 유저인지 판단해야 한다.

따라서 가입되어있다면 True를, 가입되어있지 않다면 False를 추가하고

그 정보를 parameter로 보내버렸다.

성공적으로 parameter를 통해 가입여부가 전해졌다.

회원가입, 로그인, 로그아웃

이후 갑작스럽겠지만 하루종일 고생하느라 기록을 못했다.
그래서 지금부터는 전체적인 흐름과 코드를 적겠다.

Google OAuth2 로그인

Client가 Google OAuth2를 통해 유저 데이터를 확인한다.

google 로그인 버튼을 누르면 OAuth2 로그인 페이지로 넘어간다.

이후 loginService를 통해 만약 유저가 없다면 jwt에 NoJWT를, 있다면 만든 jwt 토큰을 담아서 보낸다.

Case1 : 회원가입

위에 있는 코드를 통해 회원가입 페이지로 이동한다는 것은 확인할 수 있었다.

이후 비밀번호를 입력하고 서버로 회원가입 데이터를 보낸다.
axios를 써야 하는 GET 함수는 따로 함수화 시켜서 관리했다.

이후 signupservice를 통해 처리해 주고

이후 결과에 따라 처리해준다.

Case2 : 로그인

위와 같이 signup을 통해 로그인 데이터를 보낸다.

이때, 로그인 되어 있기 때문에 JWT 토큰을 같이 보낸다.

이때, JWT 토큰이 있다면 그대로 쿠키로 만들어 버린다.

이때, 쿠키가 있는지 바로 확인하여

로그인 여부를 확인한다.

로그아웃

그냥 쿠키를 없앤다. useEffect 덕분에 바로 반응이 된다.

잘 적용되었다!

profile
닭이 되고싶은 병아리

0개의 댓글