🌿 Spring

[Spring Security] OAuth 카카오 로그인하기

연_우리 2022. 2. 23. 01:52
반응형

목차

     

    썸네일

     

    이전글

    https://lotuus.tistory.com/80

     

    [Spring Security] OAuth 네이버 로그인하기

    목차 이전글 https://lotuus.tistory.com/79 [Spring Security] OAuth 구글 로그인하기 목차 [이전 게시글] 꼭! 봐주세여 [Spring Security] 동작방법 및 Form, OAuth 로그인하기 (Feat.Thymeleaf 타임리프) 목차..

    lotuus.tistory.com

     

     

    네이버와 동일하게 카카오는 CommonOAuth2Provider에 등록되어있지 않다.

     

     

    Spring Security - OAuth2 카카오 로그인하기

     

    카카오 설정

    사진 중간중간 파란 글씨로 작성한 내용은 application.properties에 작성될 내용이다!! 

     

     

    1. 카카오 개발자 센터 접속

     

    Kakao Developers

    카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

    developers.kakao.com

     

    2. 내 애플리케이션 > 애플리케이션 추가하기

     

    3. 애플리케이션 정보 입력 후 저장

    4. REST API가 client-id이다. 확인하고 플랫폼 설정하기 클릭

     

    5. Web 플랫폼 등록 클릭

     

    6. 사이트 도메인에 localhost:8080입력

     

    7. Redirect URI 등록하러 가기 클릭

     

    8. 카카오 로그인 활성화 "ON"으로 변경, Redirect URI 등록 클릭

     

    9. http://localhost:8080/login/oauth2/code/kakao 입력

     

    10. 왼쪽 메뉴바를 눌러서 동의항목 클릭

     

     

    11. 가져오려는 정보 설정하여 사용으로 변경

     

    12. 왼쪽 메뉴 눌러서 보안 클릭

     

    13. Client Secret 코드 생성 클릭하여 확인. 

     

     

    OAuth2 설정

    build.gradle : 이전과 동일함

     

    application.properties

    #Kakao
    spring.security.oauth2.client.registration.kakao.client-id = 
    spring.security.oauth2.client.registration.kakao.client-secret = 
    spring.security.oauth2.client.registration.kakao.scope = profile_nickname, account_email
    spring.security.oauth2.client.registration.kakao.client-name = Kakao
    spring.security.oauth2.client.registration.kakao.authorization-grant-type = authorization_code
    spring.security.oauth2.client.registration.kakao.redirect-uri = http://localhost:8080/login/oauth2/code/kakao
    spring.security.oauth2.client.registration.kakao.client-authentication-method = POST
    
    spring.security.oauth2.client.provider.kakao.authorization-uri = https://kauth.kakao.com/oauth/authorize
    spring.security.oauth2.client.provider.kakao.token-uri = https://kauth.kakao.com/oauth/token
    spring.security.oauth2.client.provider.kakao.user-info-uri = https://kapi.kakao.com/v2/user/me
    spring.security.oauth2.client.provider.kakao.user-name-attribute = id
    registration.kakao.client-name 자동 생성되는 로그인 페이지에서 노출하는 등에 사용한다(꼭 있어야하는지는 모르겠다..)
    registration.kakao.authorization-grant-type OAuth2는 4가지 Authorization Grant유형이 있다
    네이버는 가장 많이 사용되는 authorization_code 방식을 이용한다 (참고)
    registration.kakao.redirect-uri 카카오가 사용자 확인 후 정보를 내 프로젝트로 보내주는 주소
    구글처럼 패턴을 가지고 있다. "{baseUrl}/login/oauth2/code/{registrationId}"
    registration.kakao.client-authentication-method 카카오는 필수 파라미터를 POST로 요청한다고 나와있다.(참고)
    provider.kakao.authorization-uri 인증을 요청하는 url을 작성한다 (참고)
    provider.kakao.token-uri 토큰을 요청하는 url을 작성한다 (참고 > Sample > Request 링크)
    provider.kakao.user-info-uri 회원 정보를 가져오는 url을 작성한다 (참고)
    provider.kakao.user-name-attribute { "id":~, "kakao_account":{~}, "properties":{~} } 
    카카오는 위와같이 결과를 반환해준다. id로 지정한다
    (네이버는 하위필드가 존재하는 response로 잡았었는데.. 카카오는 상위필드로 잡아줘도 문제없는 것 같다..)

    token-uri 부분 참고

     

    OAuth2UserInfo 인터페이스와 KakaoUserInfo 클래스

    카카오의 경우는 providerId값을 "id"로 가져오면된다.

     

    패키지 > auth 폴더 > userinfo 폴더 > OAuth2UserInfo.java : 이전과 동일

     

    패키지 > auth 폴더 > userinfo 폴더 > KakaoUserInfo.java

    public class KakaoUserInfo implements Oauth2UserInfo{
        private Map<String, Object> attributes;
        private Map<String, Object> attributesAccount;
        private Map<String, Object> attributesProfile;
    
        public KakaoUserInfo(Map<String, Object> attributes) {
            /*
            System.out.println(attributes);
                {id=아이디값,
                connected_at=2022-02-22T15:50:21Z,
                properties={nickname=이름},
                kakao_account={
                    profile_nickname_needs_agreement=false,
                    profile={nickname=이름},
                    has_email=true,
                    email_needs_agreement=false,
                    is_email_valid=true,
                    is_email_verified=true,
                    email=이메일}
                }
            */
            this.attributes = attributes;
            this.attributesAccount = (Map<String, Object>) attributes.get("kakao_account");
            this.attributesProfile = (Map<String, Object>) attributesAccount.get("profile");
        }
    
        @Override
        public Map<String, Object> getAttributes() {
            return attributes;
        }
    
        @Override
        public String getProviderId() {
            return attributes.get("id").toString();
        }
    
        @Override
        public String getProvider() {
            return "Kakao";
        }
    
        @Override
        public String getEmail() {
            return attributesAccount.get("email").toString();
        }
    
        @Override
        public String getName() {
            return attributesProfile.get("nickname").toString();
        }
    }

     

     

    OAuth2Login loadUserByUsername

    패키지 > auth 폴더 > PrincipalOauth2UserService.java

    @Service
    public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
    
        @Autowired private UserRepository userRepository;
        @Autowired private BCryptPasswordEncoder bCryptPasswordEncoder;
    
        @Override
        public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
    
            OAuth2User oAuth2User = super.loadUser(userRequest);
            
            OAuth2UserInfo oAuth2UserInfo = null;
            String provider = userRequest.getClientRegistration().getRegistrationId();    
            
            if(provider.equals("google")){
                oAuth2UserInfo = new GoogleUserInfo(oAuth2User.getAttributes());
            }
            else if(provider.equals("naver")){
                oAuth2UserInfo = new NaverUserInfo(oAuth2User.getAttributes());
            }
            else if(provider.equals("kakao")){	//추가
                oAuth2UserInfo = new KakaoUserInfo(oAuth2User.getAttributes());
            }
            
            String providerId = oAuth2UserInfo.getProviderId();	
            String username = provider+"_"+providerId;  			
    
            String uuid = UUID.randomUUID().toString().substring(0, 6);
            String password = bCryptPasswordEncoder.encode("패스워드"+uuid); 
    
            String email = oAuth2UserInfo.getEmail();
            Role role = Role.ROLE_USER;
    
            User byUsername = userRepository.findByUsername(username);
            
            //DB에 없는 사용자라면 회원가입처리
            if(byUsername == null){
                byUsername = User.oauth2Register()
                        .username(username).password(password).email(email).role(role)
                        .provider(provider).providerId(providerId)
                        .build();
                userRepository.save(byUsername);
            }
    
            return new PrincipalDetails(byUsername, oAuth2UserInfo);	
        }
    }

     

     

     

    OAuth2Login Authentication OAuth2User

    패키지 > auth 폴더 > PrincipalDetails.java : 이전과 동일

     

     

     

    OAuth2Login Domain구현

    패키지 > domain 폴더 > Role.java : 이전과 같음 

    패키지 > domain 폴더 > User.java : 이전과 같음

     

     

     

    OAuth2Login Controller 구현

    패키지 > controller 폴더 > UserController.java : 이전과 같음

     

     

     

    OAuth2Login View구현

    resources > templates > join.html : 이전과 같음 

    resources > templates > login.html

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
    <head>
        <meta charset="UTF-8">
        <title>로그인 페이지</title>
    </head>
    <body>
    <h1>로그인 페이지</h1>
    <hr/>
    
    <h2>로그인 유저 : </h2>
    <p sec:authentication="principal"></p>
    
    <div sec:authorize="isAnonymous()" style="background-color:pink; padding:1em;">
        <form action="/login" method="post" >
            <input type="text" name="username" />
            <input type="password" name="password" />
            <button>로그인</button>
        </form>
        
        <a href="/oauth2/authorization/google">구글 로그인</a>
        <a href="/oauth2/authorization/naver">네이버 로그인</a>
        <a href="/oauth2/authorization/kakao">카카오 로그인</a>
        <!-- /oauth2/authorization/{registrationId}에 요청이 들어오면, 
        스프링 시큐리티가 provider의 authorization-uri로 요청을 전달한다-->
        <br><br>
    
        <a href="/joinForm">회원가입하기</a><br>
    </div>
    
    <div sec:authorize="isAuthenticated()" style="background-color:pink; padding:1em;">
        <a href="/logout">로그아웃</a>
    </div>
    
    <br><br>
    <a href="/user">유저</a><br>
    <a href="/manager" sec:authorize="hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')">매니저</a><br>
    <a href="/admin" sec:authorize="hasRole('ROLE_ADMIN')">어드민</a><br>
    
    <br><br>
    <a href="/form/loginInfo">Form 로그인 정보</a>
    <a href="/oauth/loginInfo">OAuth2 로그인 정보</a>
    <a href="/loginInfo">로그인 정보</a>
    
    </body>
    </html>

     

     

     

     

     

    반응형
    • 네이버 블러그 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 구글 플러스 공유하기
    • 카카오톡 공유하기