개발자의 서재
Chapter.05-1 : 스프링 시큐리티와 OAuth 2.0 으로 로그인 구현하기 본문
Chapter.05-1 : 스프링 시큐리티와 OAuth 2.0 으로 로그인 구현하기
ironmask431 2022. 2. 11. 23:27
"스프링부트와 AWS로 혼자 구현하는 웹 서비스" 라는 책을 바탕으로 학습목적의 프로젝트를 진행하고 있습니다.
소스 : https://github.com/ironmask431/springboot_aws_01
Chapter 05. 스프링 시큐리티와 OAuth 2.0 으로 로그인 구현하기
스프링시큐리티는 막강한 인증과 인가 기능을 가진 프레임워크 입니다.
스프링 시큐리티와 OAuth 2.0 을 구현한 구글 로그인을 연동하여 로그인 기능을 만들어보겠습니다.
5.1 스프링시큐리티와 OAuth2 클라이언트
많은 서비스에서 로그인기능을 id/pw 보다는 구글,페이스북,네이버같은 소셜 로그인을 사용합니다.
직접 로그인 기능 만드는 것 보다 OAuth 로그인 을 구현하면 로그인관련 기능을 구글,페이스북,네이버에 맡기면 되니
서비스개발에 집중하기 좋습니다.
5.2 구글 서비스 등록
* console.cloud.google.com 접속
프로젝트 선택
→ 새 프로젝트
→ 프로젝트명 입력하기
→ api 및 서비스
→ 사용자 인증정보
→ 사용자 인증정보 만들기
→ OAuth 클라이언트id
→ 동의화면구성
→ 사용자 유형 : 외부선택
→ 앱이름, 사용자지원이메일, 개발자연락처정보(이메일)등록
→ 다음 범위 추가 또는 삭제클릭
→ email, profile, openid 체크선택
→ 테스트사용자등록 + ADD USER
→ 내 이메일 입력..
→ 요약 내용 확인
→ 다시 사용자인증정보
→ 사용자 인증정보 만들기 OAuth 클라이언트id
→ 애플리케이션 유형 : "웹애플리케이션" 선택 / 이름 : "springboot_aws_01"
승인된 리디렉션 URI 추가 "http://localhost:8080/login/oauth2/code/google" 추가
→ 만들기
→ OAuth 클라이언트 ID와 보안비밀번호 확인 (프로젝트에서 사용)
OAuth 클라이언트 ID 생성완료.
* 승인된 리디렉션URI :
서비스에서 파라미터로 인증정보를 주었을 때 인증이 성공하면 구글에서 리다이렉트할 URI 입니다.
스프링부트2 버전의 시큐리티에서는 기본적으로 "{도메인}/login/oauth2/code/{소셜서비스코드}"
로 리다이렉트URI를 지원하고 있습니다.
사용자가 별도로 리다이렉트URI 매핑 컨트롤러를 만들지않아도됩니다. 시큐리티에서 이미 구현되어 있습니다.
현재는 개발단계이므로 "http://localhost:8080/login/oauth2/code/google" 로만 등록합니다.
실제 배포하게 되면 주소를 추가해야 합니다.
* application-oauth 등록
src/main/resources 에 application-oauth.proerperties 생성
spring.security.oauth2.client.registration.google.client-id=여기에 클라이언트id 입력
spring.security.oauth2.client.registration.google.client-secret=여기에 클라이언트 보안비밀번호 입력
spring.security.oauth2.client.registration.google.scope=profile,email
scope=profile, email 설정이유
미설정 시 기본값은 openid, profile, email 인데
openid 라는 scope 가 있으면, open Id Provider 로 인식함. 이렇게 되면 Open Id Provider 인
서비스(구글)과 그렇지 않은 서비스(네이버/카카오)로 나눠서 각각
OAuth2Service 를 만들어야합니다.
하나의 OAuth2Service를 사용하기 위해 openid scope를 제외하고 등록합니다.
스프링부트에서 properties 의 이름을 application-xxxx.properties 로 만들면 xxxx라는 이름의
profile이 생성되어 이를통해 관리 할 수 있습니다.
즉 profile=xxx 식으로 호출하면 해당 properties의 설정들을 가져올 수 있습니다.
application-oauth.proerperties 설정을 사용하기 위해
application.properties 에 코드 를 추가합니다.
spring.profiles.include=oauth
* .gitIgnore 등록
OAuth 클라이언트 ID와 보안비밀번호는 중요정보이기 때문에
깃허브에 올라가지 않도록 해야하므로 .gitignore 에 application-oauth.proerperties 를 추가한다.
5.3 구글 로그인 연동하기
사용자 정보를 담당할 User 엔티티 클래스 생성
package com.jojodu.book.springboot.domain.user;
/**
* 사용자 정보 담당 엔티티
*/
@NoArgsConstructor
@Getter
@Entity
public class User extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String email;
@Column
private String picture;
//JPA로 데이터베이스로 저장할때 Enum값을 어떤형태로 저장할지를 결정합니다.
//기본적으로는 int로 된 숫자가 저장되자만, 숫자로저장되면 db에서 확인 시 무슨의미인지 알 수없음.
//그래서 문자열(EnumType.STRING)로 저장될 수 있도록 선언
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role;
@Builder
public User(String name, String email, String picture, Role role){
this.name = name;
this.email = email;
this.picture = picture;
this.role = role;
}
public User update(String name, String picture){
this.name = name;
this.picture = picture;
return this;
}
public String getRoleKey(){
return this.role.getKey();
}
}
각 사용자의 권한을 관리할 Enum 클래스 Role 생성
package com.jojodu.book.springboot.domain.user;
/**
* 사용자의 권한관리 클래스(enum)
*/
@Getter
@RequiredArgsConstructor
public enum Role {
//스프링 시큐리티에서는 권한 코드에 항상 ROLE_ 가 앞에 있어야만합니다.
GUEST("ROLE_GUEST","손님"),
USER("ROLE_USER","일반 사용자");
private final String key;
private final String title;
}
User의 CRUD를 담당할 UserRepository.java 생성
package com.jojodu.book.springboot.domain.user;
/**
* User의 CRUD 담당
*/
public interface UserRepository extends JpaRepository<User, Long> {
//소셜로그인으로 반환되는 값중 email을 통해 이미 생성된 사용자인지
//처음 가입하는 사용자인지 판단하기 위한 메소드
//스트림으로 변환하기 위해 리턴타입을 Optional<User> 클래스로 생성
Optional<User> findByEmail(String email);
}
* 스프링시큐리티 설정
build.gradle 에 spring security / oauth2관련 라이브러리 추가
//oauth 추가 (소셜로그인등 클라이언트입장에서 소셜 기능 구현 기능)
implementation('org.springframework.boot:spring-boot-starter-oauth2-client')
* 소셜 로그인 설정 코드 작성
SecurityConfig.java
package com.jojodu.book.springboot.config.auth;
/**
* Spring Security + OAuth2 로그인 설정
*/
@RequiredArgsConstructor
@EnableWebSecurity //Spring Security 설정등을 활성화시켜줍니다.
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;
protected void configure(HttpSecurity http) throws Exception{
http.csrf().disable().headers().frameOptions().disable()
.and().authorizeRequests()
.antMatchers("/","/css/**","/images/**","/js/**","/h2-console/**").permitAll()
.antMatchers("/api/v1/**").hasRole(Role.USER.name())
.anyRequest().authenticated()
.and().logout().logoutSuccessUrl("/")
.and().oauth2Login().userInfoEndpoint().userService(customOAuth2UserService);
}
/**
* .headers().frameOptions().disable() = h2-console 화면을 사용하기 위해 해당옵션들을 disable합니다.
* .authorizeRequests() = URL별 권한 관리를 설정하는 옵션의 시작점입니다. 이후 antMatchers() 옵션을 사용가능합니다.
* .antMatchers() = 권한 관리 대상을 지정하는 옵션입니다.URL,HTTP 메소드별로 관리가 가능합니다.
* .anyRequest().authenticated() = 설정값 이외의 url에 대한 설정입니다. 이외의 url은 모두 인증된 사용자에게만 허용합니다.
* .and().logout().logoutSuccessUrl("/") = 로그아웃 성공시 "/"로 이동
* .oauth2Login() = oauth2 로그인 설정의 시작점
* .userInfoEndpoint() = oauth2 로그인 성공 후 사용자정보를 가져올때 설정담당
* .userService() = 소셜로그인성공후 후속조치를 진행할 userService 인터페이스의 구현제등록
* 소셜서비스에서 사용자정보를 가져온 상태에서 추가로 진행하고자하는 기능을 명시할 수 있음
*/
}
OAuthAttributes.java
package com.jojodu.book.springboot.config.auth.dto;
/**
* OAuth2UserService 를 통해서 가져온 oAuth2User의 attribute를 담을 클래스
*/
@Getter
public class OAuthAttributes {
private Map<String, Object> attributes;
private String nameAttributeKey;
private String name;
private String email;
private String picture;
@Builder
public OAuthAttributes(Map<String, Object> attributes, String nameAttributeKey
,String name, String email, String picture){
this.attributes = attributes;
this.nameAttributeKey = nameAttributeKey;
this.name = name;
this. email = email;
this. picture = picture;
}
//OAuth2User 정보를 OAuthAttributes에 입력
public static OAuthAttributes of(String registrationId, String userNameAttributeName,Map<String,Object> attributes){
return ofGoogle(userNameAttributeName, attributes);
}
//OAuth2User 에서 반환하는 사용자정보는 Map이기 때문에 하나하나 변환해야합니다.
public static OAuthAttributes ofGoogle(String userNameAttributeName,Map<String,Object> attributes){
return OAuthAttributes.builder()
.name((String)attributes.get("name"))
.email((String)attributes.get("email"))
.picture((String)attributes.get("picture"))
.attributes(attributes)
.nameAttributeKey(userNameAttributeName)
.build();
}
//User Entity를 생성합니다.
//OAuthAttributes 에서 엔티티를 생성하는 시점(DB insert)은 처음 로그인할때입니다.
//최초 생성할때의 기본 권한을 GUEST로 줍니다.
public User toEntity(){
return User.builder()
.name(name)
.email(email)
.picture(picture)
.role(Role.GUEST)
.build();
}
}
SessionUser.java
package com.jojodu.book.springboot.config.auth.dto;
/**
* 세션에 사용자정보 담기위한 클래스
*/
@Getter
public class SessionUser implements Serializable {
//session에 담기위해 Serializable를 구현
private String name;
private String email;
private String picture;
public SessionUser(User user){
this.name = user.getName();
this.email = user.getEmail();
this.picture = user.getPicture();
}
//SessionUser 에는 인증된 사용자정보만 필요하므로, name,email,picture만 선언합니다.
/**
* 세션에 User Entity클래스를 바로 저장하면 안되는 이유.
* -> User클래스에 직렬화를 구현하지 않았으므로, Failed to Converto from type... 에러발생
* 엔티티클래스 자체를 직렬화 한다면 여러가지 문제가 생길 수 있음.
* @OneToMany, @ManyToMany 등 자식엔티티를 가지고있다면 자식까지 직렬화되어
* 성능이슈, 부수효과가 발생 할 수 있음.
* 그래서 직렬화 기능을 가진 세션Dto(SessionUser)를 따로 만드는것이 운영유지보수에 좋음.
*/
}
CustomOAuth2UserService.java
package com.jojodu.book.springboot.config.auth;
/**
* OAuth2 로그인 이후 가져온 사용자의 정보(email, name, picture 등)
* 을 기반으로 가입, 정보수정, 세션저장 등의 기능 담당
* OAuth2UserService 인터페이스를 구현
*/
@RequiredArgsConstructor
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final UserRepository userRepository;
private final HttpSession httpSession;
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest);
//OAuth2UserService 를 통해 oAuth2User(로그인한 유저) 정보를 가져옴.
String registrationId = userRequest.getClientRegistration().getRegistrationId();
//현재 로그인 진행중인 서비스를 구분하는 코드. (구글, 네이버(=naver), 카카오(=kakao)등)
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails()
.getUserInfoEndpoint().getUserNameAttributeName();
//OAuth2 로그인 진행 시 키가되는 필드값. PK와 같은 의미
//구글의 경우 기본적으로 코드지원하지만, 네이버,카카오는 지원하지않음 구글의 기본코드는 "sub"
//네이버 카카오는 application-oauth.properties 에 정의한 user-name-attribute 값으로 설정됨.
OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName,oAuth2User.getAttributes());
//OAuthAttributes = OAuth2UserService 를 통해서 가져온 oAuth2User의 attribute를 담을 클래스입니다.
User user = saveOrUpdate(attributes);
//로그인 user정보 DB insert or update 실행
httpSession.setAttribute("user",new SessionUser(user));
//SessionUser = 세션에 사용자정보 담기위해 만든 클래스
return new DefaultOAuth2User(Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey()))
,attributes.getAttributes()
,attributes.getNameAttributeKey());
}
//구글 사용자정보가 업데이트되었을때를 대비하여 update 기능도 같이구현.
//사용자의 이름, 프로필사진이 변경되면 User엔티티에 반영됨
private User saveOrUpdate(OAuthAttributes attributes){
User user = userRepository.findByEmail(attributes.getEmail())
.map(entity -> entity.update(attributes.getName(), attributes.getPicture()))
.orElse(attributes.toEntity());
//attributes의 이메일로 user정보를 userRepository통해서 조회한다음, 일치하는 정보가 있으면
//해당 유저의 name과 picture를 업데이트하고, 해당 유저정보를 user 엔티티로 반환.
//일치하는 정보가 없으면 attributes의 정보로 새로운 user 엔티티를 만들어서 (DB insert) 반환.
return userRepository.save(user);
}
}
* 로그인 테스트
index.mustache 수정
<div class="col-md-6">
<a href="/posts/save" role="button" class="btn btn-primary">글 등록</a>
{{#userName}} <!-- userName 이 있을 경우 -->
Logged in as : <span id="user">{{userName}}</span>
<!-- 스프링시큐리티에서 기본 제공하는 로그이웃 url -->
<a href="/logout" class="btn btn-info active" role="button">Logout</a>
{{/userName}}
{{^userName}} <!-- userName 이 없을 경우 -->
<!-- 스프링시큐리티에서 기본 제공하는 oauth2 로그인url -->
<a href="/oauth2/authorization/google" class="btn btn-success active" role="button">Google Login</a>
{{/userName}}
</div>
머스테치는 다른언어와 같은 if문 을 제공하지않음 ( true, false만 반환 )
{{#userName}} ~ {{/userName}} = userName 이 있을 경우
{{^userName}} ~ {{/userName}} = userName 이 없을 경우
/logout = 스프링시큐리티에서 기본제공하는 로그아웃 url 입니다. 별도록
컨트롤러 만들필요없음.
/oauth2/authorization/google = 스프링시큐리티에서 기본제공하는 로그인url 입니다.
별도로 컨트롤러 만들필요없음.
IndexController.java 에 UserName을 model에 추가하는 코드 추가
@GetMapping("/")
public String index(Model model){
model.addAttribute("posts", postsService.findAllDesc());
SessionUser user = (SessionUser) httpSession.getAttribute("user");
if(user != null){
model.addAttribute("userName",user.getName());
}
return "index";
}
localhost:8080/ 접속
로그인버튼 클릭
로그인 성공
h2-console 에서 회원가입이 되어 있는지 확인
글 작성 테스트 시 현재 로그인한 사용자의 권한이 GUEST이기 때문에
SecurityConfig에 설정한대로 "/api/v1/**" api url은 허용되지 않아서 "403" 에러 발생
해당 유저의 ROLE 를 USER로 업데이트
로그아웃 후 재로그인 (세션의 ROLE을 새로고침하기위해) 후 글등록 정상 확인
5.4 네이버 로그인
* 네이버 로그인 API 이용 등록
https://developers.naver.com/products/login/api/api.md
애플리케이션 이름 : springboot_aws_01
네이버로그인 선택
사용 api 체크 : 회원이름 / 이메일 / 프로필사진 선택
환경추가 : pc 웹
서비스 url : http://localhost:8080/
네이버아이디 로그인 콜백 : (구글에서 등록한 리디렉션url과 같은 역할)
http://localhost:8080/login/oauth2/code/naver
client ID / Client Secret 정보 확인
* application-oauth.properties 에 네이버 로그인 정보 등록
// naver login
spring.security.oauth2.client.registration.naver.client-id=여기에 client_id
spring.security.oauth2.client.registration.naver.client-secret=여기에 client_secret
// localhost:8080/login/oauth2/code/naver (스프링 시큐리티에서 기본제공하는 형태)
spring.security.oauth2.client.registration.naver.redirect-uri={baseUrl}/{action}/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.scope=name,email,profile_image
spring.security.oauth2.client.registration.naver.client-name=naver
// 네이버 로그인 인증 요청 uri
spring.security.oauth2.client.provider.naver.authorization-uri=https://nid.naver.com/oauth2.0/authorize
// 네이버 접근 토큰의 발급,갱신,삭제 요청 uri
spring.security.oauth2.client.provider.naver.token-uri=https://nid.naver.com/oauth2.0/token
// 네이버 회원의 프로필을 조회 uri
spring.security.oauth2.client.provider.naver.user-info-uri=https://openapi.naver.com/v1/nid/me
// 기준의 되는 user-name-attribute 의 이름을 response로 등록
// 실제 유저 키깂은 reponse.id 이지만 스프링 시큐리티에서는 하위필드를 명시 할 수 없으므로,
// 상위필드인 response라고 명시
spring.security.oauth2.client.provider.naver.user-name-attribute=response
* 유저정보 조회 api response 형태
{
"resultcode": "00",
"message": "success",
"response": {
"email": "openapi@naver.com",
//email : 회원의 네이버아이디가 아님. 회원가입시 별도등록한 다른 email
"nickname": "OpenAPI",
"profile_image": "https://ssl.pstatic.net/static/pwe/address/nodata_33x33.gif",
"age": "40-49",
"gender": "F",
"id": "32742776",
//유저의 고유 key값. 같은 사용자라도 요청하는 애플리케이션에 따라 다른값.
"name": "오픈 API",
"birthday": "10-01",
"birthyear": "1900",
"mobile": "010-0000-0000"
}
}
* OauthAttributes.java 에 네이버 설정 등록
//OAuth2User 정보를 OAuthAttributes에 입력
public static OAuthAttributes of(String registrationId, String userNameAttributeName,Map<String,Object> attributes){
//registrationId = 로그인 서비스 구분 코드
//String = userNameAttributeName 은 사용자정보 조회 응답 json에서 유니크키 값.
//구글은 "sub"로 자동
//카카오 네이버는 application-oauth.properties 에 설정한 user-name-attribute 값
if("naver".equals(registrationId)){
return ofNaver(userNameAttributeName, attributes);
}else if("kakao".equals(registrationId)){
return ofKakao(userNameAttributeName, attributes);
}
return ofGoogle(userNameAttributeName, attributes);
}
//naver
public static OAuthAttributes ofNaver(String userNameAttributeName,Map<String,Object> attributes){
//네이버의 경우 회원정보로 리턴받은 json형태가 response 내부에 유저정보가 들어있으므로 아래 코드추가함.
Map<String, Object> response = (Map<String, Object>)attributes.get("response");
//네이버의 경우 userNameAttributeName 이 "response"로 되어있는데 실제 키값은 response안에 id 이므로, id라고 변경해줌.
userNameAttributeName = "id";
return OAuthAttributes.builder()
.name((String)response.get("name"))
.email((String)response.get("email"))
.picture((String)response.get("profile_image"))
.attributes(response) //user 정보 map
.nameAttributeKey(userNameAttributeName) // user정보map의 pk필드 (네이버 = id)
.build();
}
* index.mustache 에 네이버 로그인 버튼 추가
<!-- 스프링시큐리티에서 기본 제공하는 oauth2 로그인url -->
<a href="/oauth2/authorization/naver" class="btn btn-success active" role="button">Naver Login</a>
* 로그인테스트
정상 로그인 확인.
5.5 카카오 로그인
카카오 로그인 연동은 네이버와 유사하다.
카카오 디벨로퍼 접속 : https://developers.kakao.com/
내 애플리케이션 > 애플리케이션 추가하기 > 앱이름, 사업자명 등록
REST API 키 확인 (구글,네이버의 client_id 와 같은 역할)
앱설정 > 플랫폼 > web 플랫폼 등록
사이트도메인 : http://localhost:8080
제품설정 > 카카오 로그인 > 활성화 설정 on > Redirect URI 생성 >
http://localhost:8080/login/oauth2/code/kakao
제품설정 > 카카오 로그인 > 동의항목 >
닉네임(필수), 프로필사진(선택), 카카오계정(이메일)(선택) 으로 설정함.
제품설정 > 보안 > client secret : 카카오는 client secret이 선택사항이므로 패스
제품설정 > 고급 > Logout Redirect URI : 스프링시큐리티에서 로그아웃은
"/logout" 으로 기본설정되어 있으니 패스한다.
* application-oauth.properties 에 카카오 로그인 정보 등록
//kakao login
spring.security.oauth2.client.registration.kakao.client-id=여기에 REST API 키
// localhost:8080/login/oauth2/code/kakao (스프링 시큐리티에서 기본제공하는 형태)
spring.security.oauth2.client.registration.kakao.redirect-uri={baseUrl}/{action}/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.kakao.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.kakao.scope=profile_nickname,profile_image,account_email
spring.security.oauth2.client.registration.kakao.client-name=kakao
//kakao의 경우 별도로 추가해줘야함.
spring.security.oauth2.client.registration.kakao.client-authentication-method=POST
// 카카오 로그인 인증 요청 uri
spring.security.oauth2.client.provider.kakao.authorization-uri=https://kauth.kakao.com/oauth/authorize
//카카오 접근 토큰의 발급,갱신,삭제 요청 uri
spring.security.oauth2.client.provider.kakao.token-uri=https://kauth.kakao.com/oauth/token
//카카오 회원의 프로필을 조회 uri
spring.security.oauth2.client.provider.kakao.user-info-uri=https://kapi.kakao.com/v2/user/me
//카카오 회원정보 조회 응답 json 형태 확인하여 pk키값 필드 입력
spring.security.oauth2.client.provider.kakao.user-name-attribute=id
* 처음 카카오 로그인 시 [invalid_token_response] An error occurred while attempting to
retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized 오류 발생
구글링해보니
혹시, application.yml 설정에서 “client-authentication-method: POST” 설정이 있는지도 확인 해주세요~
application.properties 에 추가하고 정상 로그인됨.
* 유저정보 조회 api response 형태
{
"id":123456789, // key값
"kakao_account": {
"profile_needs_agreement": false,
"profile": {
"nickname": "홍길동",
"thumbnail_image_url": "http://yyy.kakao.com/.../img_110x110.jpg",
"profile_image_url": "http://yyy.kakao.com/dn/.../img_640x640.jpg",
"is_default_image":false
},
"name_needs_agreement":false,
"name":"홍길동",
"email_needs_agreement":false,
"is_email_valid": true,
"is_email_verified": true,
"email": "sample@sample.com",
"age_range_needs_agreement":false,
"age_range":"20~29",
"birthday_needs_agreement":false,
"birthday":"1130",
"gender_needs_agreement":false,
"gender":"female"
},
"properties":{
"nickname":"홍길동카톡",
"thumbnail_image":"http://xxx.kakao.co.kr/.../aaa.jpg",
"profile_image":"http://xxx.kakao.co.kr/.../bbb.jpg",
"custom_field1":"23",
"custom_field2":"여"
...
}
}
* OauthAttributes.java 에 카카오 설정 등록
//OAuth2User 정보를 OAuthAttributes에 입력
public static OAuthAttributes of(String registrationId, String userNameAttributeName,Map<String,Object> attributes){
//registrationId = 로그인 서비스 구분 코드
//String = userNameAttributeName 은 사용자정보 조회 응답 json에서 유니크키 값.
//구글은 "sub"로 자동
//카카오 네이버는 application-oauth.properties 에 설정한 user-name-attribute 값
if("naver".equals(registrationId)){
return ofNaver(userNameAttributeName, attributes);
}else if("kakao".equals(registrationId)){
return ofKakao(userNameAttributeName, attributes);
}
return ofGoogle(userNameAttributeName, attributes);
}
//kakao
public static OAuthAttributes ofKakao(String userNameAttributeName,Map<String,Object> attributes){
//카카오 회원정보 조회 api 리턴 json 형태를 보고 코드 작성.
Map<String, Object> kakao_account = (Map<String, Object>)attributes.get("kakao_account");
Map<String, Object> profile = (Map<String, Object>)kakao_account.get("profile");
//profile 에 유저정보가 들어있지만, email과 id(pk)는 밖에있으므로, profile에 추가해준다.
profile.put("email",kakao_account.get("email"));
profile.put("id",attributes.get("id"));
return OAuthAttributes.builder()
.name((String)profile.get("nickname"))
.email((String)profile.get("email"))
.picture((String)profile.get("profile_image_url"))
.attributes(profile) //user 정보 map
.nameAttributeKey(userNameAttributeName) // user정보map의 pk필드 (카카오 = id)
.build();
}
* index.mustache 에 카카오 로그인 버튼 추가
<!-- 스프링시큐리티에서 기본 제공하는 oauth2 로그인url -->
<a href="/oauth2/authorization/kakao" class="btn btn-warning active" role="button">kakao Login</a>
* 로그인테스트
정상로그인 확인.
'SpringBootProject > SpringBoot_ Oauth_AWS' 카테고리의 다른 글
Chapter.06 : AWS 서버 환경을 만들어보자 - AWS EC2 (0) | 2022.02.19 |
---|---|
Chapter.05-2 : 스프링 시큐리티와 OAuth 2.0 으로 로그인 구현하기(코드 개선 + 테스트) (0) | 2022.02.18 |
Chapter.04 : 머스테치로 게시판 화면 구성하기 (0) | 2022.02.11 |
Chapter.03 : 스프링부트에서 JPA 로 데이터베이스를 다뤄보자 (0) | 2022.02.11 |
Chapter.02 : 스프링부트에서 테스트 코드를 작성하자. (0) | 2022.02.11 |