목차
이전글
네이버와 동일하게 카카오는 CommonOAuth2Provider에 등록되어있지 않다.
Spring Security - OAuth2 카카오 로그인하기
카카오 설정
사진 중간중간 파란 글씨로 작성한 내용은 application.properties에 작성될 내용이다!!
1. 카카오 개발자 센터 접속
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로 잡았었는데.. 카카오는 상위필드로 잡아줘도 문제없는 것 같다..) |
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>
'Backend' 카테고리의 다른 글
자바, Spring Boot로 크롤링하기 - Selenium 이용 (동적페이지), 속도 개선 방법 (0) | 2022.03.08 |
---|---|
자바, Spring Boot로 크롤링하기 - Jsoup 이용 (정적페이지) (0) | 2022.03.07 |
[JPA] 값 타입(기본값, @Embedded, 값타입 컬렉션) (0) | 2022.02.22 |
[JPA] 프록시와 즉시로딩, 지연로딩 / 영속성 전이와 고아객체 (0) | 2022.02.21 |
[JPA] 상속관계 매핑, 공통 속성 매핑 (0) | 2022.02.21 |