0. Kanbanboard
1. 로그인 form
<a class="btn-login join_btn btn_click" id="kakao-login-btn" href="/oauth2/authorization/kakao">
<img alt="카카오" src="https://www.gb.go.kr/Main/Images/ko/member/certi_kakao_login.png"
style="max-width: 40%; height: auto; display: block; margin: 10px auto;">
</a>
<a href="/oauth2/authorization/google">
<img alt="구글" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGwAAAAaCAYAAABSHbkRAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAhuSURBVGhD7Zp7bFPXHce/19dvO3bsOK+ahCQmD8CEQNgKg1KoQJXasYLUSBOTEH2ok6aNPTRV1SqtmlSp09D2x7SHWm1Qui4QSJsABcIIsCSIhLxgkOZlEofYSUicOH4/r+/dufYFwqN50NEFyR/p2j6Pe865v+/v97vnXpl64X33DiR5aogLppSGpBXlkhVKGacU6pMsIpw+yl3dHumLQcHEBdu9Lrx277a0d2laJBH6JFlERBk2+OvKsV+22lJsIiYaoaRUMCUp1uJFIhYp6KhXyWsl4isYJkLHW5IsWhgmENcoLhjAJr6SLHoEwZI8LcxfMI4DFwyA9bjAul3kdzBel+SbZV6CcdEIApUH4dr3Bpw/2Ann7h1w/fwtBI8fA8dEhV5JvgnmFIyLRuH94D34P/4QzNAgKJU6fjA3+xCsqQLrmBB6LpxIKACX241ILHEP9ZPoDUYXdj+NBH3w+MNCaWEEfS74QxGhROBiuNXXjWn/VzghySgBr4es2QPma932OUxY+jA6HRDK82cOwTiEzx5AuOk8RDo9NL/ZD/2haug/qYHm3feh/e0fQWcbhb4LY9TSif1/+AuOHP4nfr//IOzOEL5sPoGWQafQY34M9Lah/vwgWelC4WCpq8P1ASs8Y1ZcaulGLBbFxcZzsE6SdP8gRMyOc7X460cHcOTTj/Gnjz5B8HFVI2P1NDeitd8hVMwfeumWt4vLjMH8NYVp64W6e8T8wORPyAQTUFR8ANmmraDEErjJUwCzxISIPAUh4oxMDJCKKeGkeUA8teXyBcQy12HPq9tBOXsxzWZCL2dhMOZBzkzhVGUV2obGYB+2w6AV42JDGwaut6Cj1448Uz6kdMLXWBJhEYUKOnoK9Y2d6Oq8hO5hP0z5RohFZE2xAC6euYDMpTnobrkAH21A1GkhY/uh17AQqVNx7fxpXP5PDzJMxRixdMHl96GpoQHqTBPSNfL4PGH3KCpPX0bFntfx/MZnMWW5AonRDDXnxvm6U7jYfBX6rBykquSYtPfjbE0NeoZcMJJ5aTaExrovcLHNAsdtG3TZz2Cq5wYCGSbka1n8+2wtmjp7oM8wQqtOzPcg9R1j9XafdnL2CGNJqokOQPFcGLKN3wGohCg/Ohi879j/RXhh+w8yjrl4BYbaT+HTquPQrX4Rm9flYNTahelQEM3Vn8OrXoayXDWudveT1OXGtcZrSC9ejehYO3pve4SBSBqdHEfX8DTpM4mGrkEUrSmH43oTbE4h3dBSeAZ7YJ90oulKO65198FqIcYSk3rbDYw7olhqyoFaYxTE4RASp2JdkQ5nT15GRLiuCNlkSZUypGlVcDmnsOb5HchWU2g4Wo3JWBaeXWnEP44chdN5G0eqqmBYtQH66Aiqa1thaa3B1dtBbCjLQXvbjRlpn0N7fTWc4iUozU/FoZp/gZnDjnNvOohxOaLTzHH8YS5+eIIcxt0cpnxkBym0zRftM4V4+xc/RmmeEucO/x2tPbdJrYhkiyiGvQxK1pqxcnkJaD5K+JalxSgzr0Ruho5E9L1UFG8lfXhfMuaaYC4qQa6ORYy9syIxCkrzcOlCE8QaHSaHb6Cv30WcwZA4lxIjOysNKqUeOiIIP9DqlatQWGCCmAnddUSORAnImPz6LN1X8VnlAdycmIbFG0bphjKUln8LGb4IfEE/6ZOGsjIzzGUl8DvtcE+5sHxFOUqWFyNbyAwJWDhGhzBmG0Bvnw1KWozYHJacVTBOJIdbbsbvXDmotjaSxScGq/6pCsf2qfDiKnG8vEQvSlz8POFIDm84cQgn24aQV1wOIzGU0+WLt1Fk0ZlKDkM2G4ZtI8RQZM74tGz8i29/CKJfoktifQ9izC/Arf7ueFTkyKMYp5RIV0ruM0006kEgwiQKjxhGqTeC9nvQ0mFFobkchhQZaIkceYoYBgaGYB+wYFwhhlwqI5pPwWq1wzYyDKnGAKVKhVvWfoyPjcA5c40kElQpWuQuW46t20mWWW+GVMhiX8WsglG0Eh0Zv8KJcD7+fOMwjt48g1H/BCZDDtT0tuNMlxtiGtiygo57+HyhKBpbXqqAYvwajlXXgjaVYePafKi1eqiIEZ575WX4LM2oO32eaMBCIlMhS6+JO0VKWhbU0nuiSRVq6PVKiKVqpOnVpIZCSnomZPzCBLTpOcgvKoIpOx2l5mUozFsFsVgEpS4NaqUcmsx8otgoLONu6HQGKGQi0DIF0gz6u9clVuixZ28Fbn3ZhKPHPgOXsx6FGanYWvEqPP1XUFvXhl07dyIj3Yhdr3wXV07XoONWCDt3bULJpl3QMA4cO1WPKZIdeMlUqTpoUhTYuGMvov3t+Pz4SQS4uV/nUpvfc3xv77edW197qehnQt19MGwM+zv/huODvPE4aIhh+ItwhX2QRYqxO2cffrg5g6Qu4YQFwrLkxi+aeTLZvTUeRcuEDMrQMMbDBXjztZchFVLjk4IjjkElXq3ODrEBb4f71kzKvAjUDK/lyHWBjMdXOYfaUHXmJrIzOQzYvXjzrTeglc/MFOR8MsDM8x/knQ8732key+2ZfZdIEJFJN2SVwUA8zBX2wBnmn5sYrEgz4fXSF/D91SVkN/b4744fXiRFdlEFUNEsVIYibNu2AXISDU+a2Yx1H6TfQ30fUceX71TJNZkkQ0hBy/XYum07dCppouEujxjzAe7sEueMsJnwnhX3BvJJpiBizvMik3xt7kTYglyXF4iPOJocSbH+Pzz5XJPkf0pSsKeMpGBPGXHBHNMhbzjCPN4r7yRPnGAo4vUEYiH+d/xfU76RVl2RZqxITDHK5L8FFhkkpIIxiWcwkNefkl3qjQsW9jgkPqdVwYa95GkuJvRMsjigIZFro8rMwoBUro39F3CHghJd8v4pAAAAAElFTkSuQmCC"
style="max-width: 40%; height: auto; display: block; margin: 10px auto;">
</a>
<a href="/oauth2/authorization/naver">
<img alt="네이버" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGwAAAAdCAYAAABPGImpAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVUSURBVGhD7ZoNTNRlHMe//7uD452D450QAXnxBVIsDSVNoVmpy6ZrZnMFZblVS6xGM0tbodWWa2u2Zk2YVGaW1rCWFpYx302nYmGBvCvE+/v7Xb/nuQc44AjI+2/8t//n9tx+z++5e+74f3+/3/P7s5N0Z9ctMveZMyFJ4VCZvJjNNySzlCJpT68rpGmExasyySnS0JMqlnKIYIKpKAhVMIWhCqYwVMEUhiqYwlAFUxiTWjAXjR5eOlcYaITp/YR3JBKNeNcwy2QU2D5T9b5iJj8hjkb46NzFzH6wG2ezsG+LRPdo7InYwO3jTdfwfHEmt1d534UdU9Zye2fld8iuyeO2LV4MfBCfVOei3dTN56u953EhfmspwAqvOXihOAuRTgF4OWgFesx9eIf2q+iuh1bSoGD2LkRe2oSHDLNR1l2H/PZyTHcORqjeBz82XsZyen+yZyzSSvbxvRl6jQN2hKyFhiluxfWOW/i4+mdu3+sRg2lO/ty25ljjVVTSZwc4GPBu6GMkkA8utZXg9fID/Ptvu2M1rnfewpe1p8Q77IPdMsxVq0eUUyAfG/2TscY4n/s9tM4DfoPWhftG40nfRXDSOIrZSJxp7WDUJmTVnEBOw+/4JjqN/oChVzvJcxai6bMYUSTuEo+Z3LYFEz27Ng/7KIj6Ry4FGwuyobDPGBwpvvch3MmS8VnTNuJIwyUk/fE2anubkSGCUy5kK4m7w1IR6GgQs4nh5+CJ+ykb4lynCI+FxR7TcaHtBk63/I2jjVdQ1d2EWJcQsTpItHMQFrpHIYYyTJIknoHsMRwt+ZJJYJZ5/YNVCmvymguQ+c+vQwbLrMbedr7vXNdwHK4/DzM9Pq89iQXukeKd8iCbYEadGz4Nf4bicVi9GQfedN7Mc4ugUhQgPBaCHb1R3lUnZqDSV4sQKnnDiXWZQoLHccHXGhNwYsYb2Gkj8vUaHZ71T8L51qKBwcpneul+8Qrb+Dp44CaJ1mc24XJ7KVZ6xdOFlPCo8R6coz3kRBbBzrYW8ohbZrgTT/stFd7xU9BxExmV3+JQ3TnhsdDQ20ZiuokZE9aNfK1iNsiButPYXvE19tP5wUbite1IL/tCrA7FUdIhyplKttVgwaKTtOIVI2HB2NDXzu0nCj/iQp2JfYs3Na+OIfbtIotgv9A58GHVUW4nTLBEPOJ9N4/6XaHreVNgTV7Ln1jqOROedBYG0mE/x2UqLrTeEKuDsDMsgZfEIOGxTaepB5tLPkM9ib7Gez51or7cZoHBAs4W7DsxkU2UXYzK7gasL9yNhfnbeKPVZurifrmQrSS+VnaAZ8pEeO9mDvR0MZr6OpBJjUWXqVesWKjpacFW2vfYjC04FL0ZzxXvRZd56Gt+aroKF2qAHqDsdqeGJ7c5X6wMhZ0/bBxpvEgNzEVeXlk5Y3YO+ViGsdacdZnWY4FbFKp7mrhtFG374z6JeCVoJbf7yW3Kx5W2UjGzH3Zr65cZ4vB9TDq3Wbu9tfwrOpDDcHLWmwPlhbXU/Zk3Hmy19bawbutHY3hb/7DXXGygTO5HS2cQuxAmq8yq6WlGH3lG41TLX9hLTUiK72IE643IqDgsVvoZLU//P7Lch+2pPo4Pbv3A7ZeCluMpvyXcHus+bDisRWdlrbCzigSLH0Ow90mwNOEZiUWwWSRYtvDYDxZYW4JXjSiHB+vOTChAx4PdBJMTXr6oencPK3/WsHu0DnHDbYvx7KEEZDvD7Alrn8e60P8lFmM8eygBRQimMogqmMJQBVMYqmAKQxVMYaiCKQwmmLz/XlaxJ0UayYRU9rtt4VCZrLDf1puQ+i931dlOPsjCpAAAAABJRU5ErkJggg=="
style="max-width: 40%; height: auto; display: block; margin: 10px auto;">
</a>
2. build.gradle
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
3. application.yml
security:
oauth2:
client:
provider:
kakao:
authorization-uri: https://kauth.kakao.com/oauth/authorize
token-uri: https://kauth.kakao.com/oauth/token
user-info-uri: https://kapi.kakao.com/v2/user/me
user-name-attribute:
naver:
authorization-uri: https://nid.naver.com/oauth2.0/authorize
token-uri: https://nid.naver.com/oauth2.0/token
user-info-uri: https://openapi.naver.com/v1/nid/me
user-name-attribute: response
registration:
kakao:
client-id:
client-secret:
client-authentication-method: POST
redirect-uri: http://localhost:8080/login/oauth2/code/kakao
authorization-grant-type: authorization_code
client-name: Kakao
scope:
- account_email
- profile_nickname
naver:
client-id:
client-secret:
redirect-uri: http://localhost:8080/login/oauth2/code/naver
authorization-grant-type: authorization_code
client-name: Naver
scope:
- email
- nickname
- name
google:
client-id:
client-secret:
redirect-uri: http://localhost:8080/login/oauth2/code/google
scope:
- email
https://lotuus.tistory.com/104
[Spring Security] OAuth 카카오 로그인하기
목차 이전글 https://lotuus.tistory.com/80 [Spring Security] OAuth 네이버 로그인하기 목차 이전글 https://lotuus.tistory.com/79 [Spring Security] OAuth 구글 로그인하기 목차 [이전 게시글] 꼭! 봐주세여 [Spring Security] 동
lotuus.tistory.com
작성한 코드를 반영하여 작성하였습니다.
4. 각각의 개발자 센터
1. 카카오
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
2. Naver
https://developers.naver.com/main/
NAVER Developers
네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음
developers.naver.com
3. 구글
https://console.cloud.google.com/apis/dashboard?pli=1&project=tranquil-osprey-380908
Google 클라우드 플랫폼
로그인 Google 클라우드 플랫폼으로 이동
accounts.google.com
5. 디자인 가이드
1. kakao
https://developers.kakao.com/docs/latest/ko/kakaologin/design-guide
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
2. Naver
https://developers.naver.com/docs/login/bi/bi.md
로그인 버튼 사용 가이드 - LOGIN
네이버 로그인은 애플리케이션에 사용할 수 있는 네이버 로그인 버튼 기본 이미지를 제공합니다. 애플리케이션의 상황에 맞게 버튼 이미지의 디자인을 변경할 수 있지만 네이버 고유의 아이덴
developers.naver.com
3. 구글
https://developers.google.com/identity/branding-guidelines?hl=ko
로그인 브랜드 가이드라인 | Google ID 플랫폼 | Google for Developers
로그인 브랜드 가이드라인 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 모바일 또는 웹 앱에서 기본적인 profile 또는 email 범위로 Google 로그인을 사용하고
developers.google.com
7. Oauth2 interface
package com.portfolio.ohousev1.auth;
import java.util.Map;
public interface OAuth2UserInfo {
Map<String, Object> getAttributes();
String getProviderId();
String getProvider();
String getEmail();
String getName();
String getNickname();
8. Oauth2 Userinfo
이메일을 PK로 지정했기때문에 member table 이메일기준으로 저장된다.
1. kakao
package com.portfolio.ohousev1.auth;
import java.util.Map;
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) {
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 attributesAccount.containsKey("name") ? attributesAccount.get("name").toString() : attributesProfile.get("nickname").toString();
}
@Override
public String getNickname() {
return attributesProfile.get("nickname").toString();
}
}
2. Naver
package com.portfolio.ohousev1.auth;
import java.util.Map;
public class NaverUserInfo implements OAuth2UserInfo{
private final Map<String, Object> attributes; //OAuth2User.getAttributes();
private final Map<String, Object> attributesResponse;
public NaverUserInfo(Map<String, Object> attributes) {
this.attributes = (Map<String, Object>) attributes.get("response");
this.attributesResponse = (Map<String, Object>) attributes.get("response");
}
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
@Override
public String getProviderId() {
return attributesResponse.get("id").toString();
}
@Override
public String getProvider() {
return "naver";
}
@Override
public String getEmail() {
return attributes.get("email").toString();
}
@Override
public String getName() {
return attributes.get("name").toString();
}
@Override
public String getNickname() {
return attributes.get("nickname").toString();
}
}
3. 구글
package com.portfolio.ohousev1.auth;
import java.util.Map;
public class GoogleUserInfo implements OAuth2UserInfo{
private final Map<String, Object> attributes;
public GoogleUserInfo(Map<String, Object> attributes) {
this.attributes = attributes;
}
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
@Override
public String getProviderId() {
return attributes.get("sub").toString();
}
@Override
public String getProvider() {
return "google";
}
@Override
public String getEmail() {
return attributes.get("email").toString();
}
@Override
public String getName() {
return attributes.get("name").toString();
}
@Override
public String getNickname() {
return (attributes.get("nickname") != null) ? attributes.get("name").toString() : null; }
}
9. OAuth2UserService
package com.portfolio.ohousev1.service.member;
import com.portfolio.ohousev1.auth.GoogleUserInfo;
import com.portfolio.ohousev1.auth.KakaoUserInfo;
import com.portfolio.ohousev1.auth.NaverUserInfo;
import com.portfolio.ohousev1.auth.OAuth2UserInfo;
import com.portfolio.ohousev1.dto.post.PostPrincipal;
import com.portfolio.ohousev1.entity.constant.RoleType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Set;
import java.util.UUID;
@Service
@Slf4j
@Transactional(readOnly = true)
public class OAuth2UserService extends DefaultOAuth2UserService {
private final MemberService memberService;
public OAuth2UserService(MemberService memberService) {
this.memberService = memberService;
}
@Override
@Transactional
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(userRequest);
OAuth2UserInfo oAuth2UserInfo = null;
String provider = userRequest.getClientRegistration().getRegistrationId();
switch (provider) {
case "google" -> oAuth2UserInfo = new GoogleUserInfo(oAuth2User.getAttributes());
case "naver" -> oAuth2UserInfo = new NaverUserInfo(oAuth2User.getAttributes());
case "kakao" -> oAuth2UserInfo = new KakaoUserInfo(oAuth2User.getAttributes());
}
// nameAttributeKey
String providerId = oAuth2UserInfo != null ? oAuth2UserInfo.getProviderId() : null;
String name = provider + "_" + providerId;
String dummyPassword = "{bcrypt}" + UUID.randomUUID();
String email = oAuth2UserInfo != null ? oAuth2UserInfo.getEmail() : null;
String nickname = oAuth2UserInfo.getNickname();
Set<RoleType> roleTypes = Set.of(RoleType.USER);
log.info("cause" + providerId, name, dummyPassword, email, nickname, roleTypes);
return memberService.searchEmail(email).map(PostPrincipal::from)
.orElseGet(() -> {
assert email != null;
return PostPrincipal.from(memberService.saveMember(
email,
dummyPassword,
roleTypes,
name,
nickname,
null
));
});
}
}
유정정보를 받아오고 그 받아오는 값을 권한을 주고 DB에저장시킵니다.
1. kakao
- 이름
2. naver
- 이름
3. Google
비밀번호는 dummy 값으로 넣고 bcypt형태로 암호화한후 저장하고,
닉네임은 못가져올경우 앞에 가져오는 oauth2(ex naver, kakao,google)앞에 붙이고 provideID값을 넣고,
권한은 USER
생일은 null 값을 넣어준다.
10.SecurityConfig
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity
public class SecurityConfig {
private final OAuth2UserService oAuth2UserService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
.csrf((csrf) -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers(new AntPathRequestMatcher("/mysql/**")))
.headers((headers) -> headers
.addHeaderWriter(new XFrameOptionsHeaderWriter(
XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)));
// login 설정
http
.oauth2Login(httpSecurityOAuth2LoginConfigurer -> httpSecurityOAuth2LoginConfigurer
.loginPage("/login")
.userInfoEndpoint()
.userService(oAuth2UserService));
http
.logout((logout) -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/members/logout"))
.permitAll()
.logoutSuccessUrl("/")// logout에 성공하면 /로 redirect
.invalidateHttpSession(true));
return http.build();
https://github.com/nodwon/OhouseV1
GitHub - nodwon/OhouseV1: 지금까지 공부한것을 기반으로 포트폴리오 제작
지금까지 공부한것을 기반으로 포트폴리오 제작. Contribute to nodwon/OhouseV1 development by creating an account on GitHub.
github.com
'포트폴리오 > ohouseClone' 카테고리의 다른 글
9.일반 로그인 만들기 (0) | 2023.11.02 |
---|---|
8. 메인페이지 & 마이페이지 제작(Card) thymeleaf (0) | 2023.11.01 |
6. 게시판 서비스 개발(spring + mysql) crud (0) | 2023.10.24 |
5. SpringSecurity 설정 및 customlogin페이지 제작 (0) | 2023.09.05 |
4. 게시판 작성 front & member api (0) | 2023.09.05 |