Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/#84 add oauth #85

Merged
merged 22 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
499e985
refactor: oauth ๊ฐœ๋ฐœ ์ „ ํด๋” ๊ตฌ์กฐ ๋ฆฌํŒฉํ† ๋ง
dong2ast Aug 11, 2023
739fd3d
feat: oauth2 ๊ด€๋ จ ์ดˆ๊ธฐ ์„ค์ • ๋ฐ google ๋กœ๊ทธ์ธ ๊ตฌํ˜„ | member ๋„๋ฉ”์ธ ์—ฐ๊ฒฐ์— ๋Œ€ํ•œ ์„ธ๋ถ€์‚ฌํ•ญ์€ ์•„์ง ๊ตฌํ˜„ x
dong2ast Aug 11, 2023
01a5911
feat: oauth ํšŒ์› ๊ฐ€์ž… ๋กœ์ง ๋ฐ ๋กœ๊ทธ์ธ ๋กœ์ง ๊ตฌํ˜„ | ํšŒ์› ๊ฐ€์ž… ํ›„ ์ถ”๊ฐ€์ •๋ณด ๋ฆฌ๋‹ค์ด๋ ‰ํŒ… ํ•„์š”
dong2ast Aug 12, 2023
922202d
feat: oauth ํšŒ์› ๊ฐ€์ž… ํ›„ ์ถ”๊ฐ€์ •๋ณด ์‚ฌ์ดํŠธ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋ฐ ํ† ํฐ ๋ฐ˜ํ™˜ ๋กœ์ง ๊ตฌํ˜„
dong2ast Aug 13, 2023
0b50264
feat: Member ํ•„๋“œ์— social ID ํ•„๋“œ ์ถ”๊ฐ€ ๋ฐ ํ•ด๋‹น ๊ฐ’์œผ๋กœ ํšŒ์›๊ฐ€์ž… ์—ฌ๋ถ€ ์กฐํšŒ ๋กœ์ง ๊ตฌํ˜„ (๊ตฌ๊ธ€, ๋„ค์ด๋ฒ„, โ€ฆ
dong2ast Aug 13, 2023
301c007
feat: ์†Œ์…œ ๋กœ๊ทธ์ธ ์‹คํŒจ handler ์ถ”๊ฐ€
dong2ast Aug 13, 2023
bea4040
Add/#82 fix auditing (#83)
dong2ast Aug 14, 2023
c2937f9
refactor: oauth ๊ฐœ๋ฐœ ์ „ ํด๋” ๊ตฌ์กฐ ๋ฆฌํŒฉํ† ๋ง
dong2ast Aug 11, 2023
45a2139
feat: oauth2 ๊ด€๋ จ ์ดˆ๊ธฐ ์„ค์ • ๋ฐ google ๋กœ๊ทธ์ธ ๊ตฌํ˜„ | member ๋„๋ฉ”์ธ ์—ฐ๊ฒฐ์— ๋Œ€ํ•œ ์„ธ๋ถ€์‚ฌํ•ญ์€ ์•„์ง ๊ตฌํ˜„ x
dong2ast Aug 11, 2023
3cf057b
feat: oauth ํšŒ์› ๊ฐ€์ž… ๋กœ์ง ๋ฐ ๋กœ๊ทธ์ธ ๋กœ์ง ๊ตฌํ˜„ | ํšŒ์› ๊ฐ€์ž… ํ›„ ์ถ”๊ฐ€์ •๋ณด ๋ฆฌ๋‹ค์ด๋ ‰ํŒ… ํ•„์š”
dong2ast Aug 12, 2023
abc1752
feat: oauth ํšŒ์› ๊ฐ€์ž… ํ›„ ์ถ”๊ฐ€์ •๋ณด ์‚ฌ์ดํŠธ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋ฐ ํ† ํฐ ๋ฐ˜ํ™˜ ๋กœ์ง ๊ตฌํ˜„
dong2ast Aug 13, 2023
f5c43d9
feat: Member ํ•„๋“œ์— social ID ํ•„๋“œ ์ถ”๊ฐ€ ๋ฐ ํ•ด๋‹น ๊ฐ’์œผ๋กœ ํšŒ์›๊ฐ€์ž… ์—ฌ๋ถ€ ์กฐํšŒ ๋กœ์ง ๊ตฌํ˜„ (๊ตฌ๊ธ€, ๋„ค์ด๋ฒ„, โ€ฆ
dong2ast Aug 13, 2023
118e176
feat: ์†Œ์…œ ๋กœ๊ทธ์ธ ์‹คํŒจ handler ์ถ”๊ฐ€
dong2ast Aug 13, 2023
471ed1e
Merge remote-tracking branch 'origin/feat/#84-add-oauth' into feat/#8โ€ฆ
dong2ast Aug 14, 2023
47de284
feat: ์†Œ์…œ ๋กœ๊ทธ์ธ ์ „์šฉ ํšŒ์›๊ฐ€์ž… controller ์ƒ์„ฑ | ์ฒซ ์†Œ์…œ ๋กœ๊ทธ์ธ์‹œ ๋ฐœ๊ธ‰๋œ access token์„ ํ†ตํ•ด ๊ฒ€์ฆ
dong2ast Aug 14, 2023
c9c00ed
fix: auditing ์—๋Ÿฌ ์ˆ˜์ •
dong2ast Aug 14, 2023
51e896a
feat: ์†Œ์…œ ๋กœ๊ทธ์ธ ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๊ตฌํ˜„ (์ž„์˜๋กœ ๋งŒ๋“  ๊ฐ์ฒด์— ์ƒˆ๋กœ ํšŒ์›๊ฐ€์ž…ํ•œ ๋ฐ์ดํ„ฐ ๋„ฃ๊ธฐ)
dong2ast Aug 14, 2023
513906c
fix: Jwt ๊ธฐ์กด ์ธ์ฆ ํ† ํฐ์— ๋งž๊ฒŒ Oauth2 ๋ณ€๊ฒฝํ•˜๋Š” ๋กœ์ง ์ถ”๊ฐ€
dong2ast Aug 14, 2023
445dbc3
refactor: ๋งˆ๊ฐ์ž„๋ฐ• ๋ถํ† ํฌ ์กฐํšŒ ๋ฆฌํŒฉํ† ๋ง (#87)
onpyeong Aug 15, 2023
5a8a770
fix: unused import ์ œ๊ฑฐ
dong2ast Aug 15, 2023
3775f87
chore: ์ฃผ์„ ๋ณ€๊ฒฝ
dong2ast Aug 15, 2023
55fd04b
feat: ์นด์นด์˜ค, ๋„ค์ด๋ฒ„ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„
dong2ast Aug 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ dependencies {
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

//OAuth 2.0
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'

// S3 AWS
implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-aws', version: '2.2.6.RELEASE'
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/org/sophy/sophy/InitDb.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void dbInit() {
.password(passwordEncoder.encode("Iammember10!"))
.phoneNum("01012345678")
.marketingAgree(true)
.authority(Authority.ROLE_USER)
.authority(Authority.USER)
.build();
em.persist(citizen);

Expand All @@ -56,7 +56,7 @@ public void dbInit() {
.password(passwordEncoder.encode("sophy123"))
.phoneNum("01012345678")
.marketingAgree(false)
.authority(Authority.ROLE_AUTHOR)
.authority(Authority.AUTHOR)
.build();
author1.setAuthorProperty(memauthor1);

Expand All @@ -66,7 +66,7 @@ public void dbInit() {
.password(passwordEncoder.encode("sophy234"))
.phoneNum("01023456789")
.marketingAgree(false)
.authority(Authority.ROLE_AUTHOR)
.authority(Authority.AUTHOR)
.build();
author2.setAuthorProperty(memauthor2);

Expand All @@ -76,7 +76,7 @@ public void dbInit() {
.password(passwordEncoder.encode("sophy345"))
.phoneNum("01098765432")
.marketingAgree(false)
.authority(Authority.ROLE_AUTHOR)
.authority(Authority.AUTHOR)
.build();
author3.setAuthorProperty(memauthor3);

Expand Down Expand Up @@ -194,7 +194,7 @@ public void dbInit() {
.password(passwordEncoder.encode("Iamoperator10!"))
.phoneNum("01056784321")
.marketingAgree(true)
.authority(Authority.ROLE_OPERATOR)
.authority(Authority.OPERATOR)
.build();
oper.setOperatorProperty(memOper);
em.persist(oper);
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/org/sophy/sophy/config/auth/CustomOAuth2User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.sophy.sophy.config.auth;

import java.util.Collection;
import java.util.Map;
import lombok.Getter;
import org.sophy.sophy.domain.enumerate.Authority;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;

@Getter
public class CustomOAuth2User extends DefaultOAuth2User {

private final String email;
private final Authority authority;

/**
* Constructs a {@code DefaultOAuth2User} using the provided parameters.
*
* @param authorities the authorities granted to the user
* @param attributes the attributes about the user
* @param nameAttributeKey the key used to access the user's "name" from
* {@link #getAttributes()}
*/
public CustomOAuth2User(
Collection<? extends GrantedAuthority> authorities,
Map<String, Object> attributes, String nameAttributeKey,
String email, Authority authority) {
super(authorities, attributes, nameAttributeKey);
this.email = email;
this.authority = authority;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.sophy.sophy.config;
package org.sophy.sophy.config.auth;

import lombok.RequiredArgsConstructor;
import org.sophy.sophy.jwt.JwtExceptionFilter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package org.sophy.sophy.config;
package org.sophy.sophy.config.auth;

import java.util.Arrays;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.sophy.sophy.config.auth.common.CustomOAuth2UserService;
import org.sophy.sophy.config.auth.common.OAuth2LoginFailureHandler;
import org.sophy.sophy.config.auth.common.OAuth2LoginSuccessHandler;
import org.sophy.sophy.jwt.JwtAccessDeniedHandler;
import org.sophy.sophy.jwt.JwtAuthenticationEntryPoint;
import org.sophy.sophy.jwt.JwtExceptionFilter;
Expand All @@ -12,6 +15,7 @@
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
Expand All @@ -31,6 +35,9 @@ public class SecurityConfig {

private final JwtExceptionFilter jwtExceptionFilter;
private final RedisTemplate redisTemplate;
private final CustomOAuth2UserService customOAuth2UserService;
private final OAuth2LoginSuccessHandler oAuth2LoginSuccessHandler;
private final OAuth2LoginFailureHandler oAuth2LoginFailureHandler;

@Bean
public PasswordEncoder passwordEncoder() {
Expand All @@ -42,7 +49,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
//CSRF ์„ค์ • Disable
http.csrf().disable()

.cors(cors -> cors.disable())
.cors(AbstractHttpConfigurer::disable)

//exception handling ํ•  ๋•Œ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€
.exceptionHandling()
Expand All @@ -64,18 +71,19 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.and()
.authorizeRequests()
.antMatchers("/author/**").hasRole("AUTHOR")
.antMatchers("/auth/**").permitAll()
.antMatchers("/profile/**").permitAll()
.antMatchers("/actuator/**").permitAll()
.antMatchers("/health/**").permitAll()
.antMatchers("/home/**").permitAll()
.antMatchers("/booktalk/search/**").permitAll()
.antMatchers("/auth/**", "/profile/**", "/actuator/**", "/health/**").permitAll()
.antMatchers("/home/**", "/booktalk/search/**", "/").permitAll()
.antMatchers("/swagger-ui/**", "/v3/api-docs/**", "/api-docs/**", "/swagger-ui.html").permitAll()
.anyRequest().authenticated() //๋‚˜๋จธ์ง€ API๋Š” ์ „๋ถ€ ์ธ์ฆ ํ•„์š”
.anyRequest().authenticated();//๋‚˜๋จธ์ง€ API๋Š” ์ „๋ถ€ ์ธ์ฆ ํ•„์š”

//JwtFilter ๋ฅผ addFilterBefore ๋กœ ๋“ฑ๋กํ–ˆ๋˜ JwtSecurityConfig ํด๋ž˜์Šค๋ฅผ ์ ์šฉ
http.oauth2Login()
.successHandler(oAuth2LoginSuccessHandler) // ๋™์˜ํ•˜๊ณ  ๊ณ„์†ํ•˜๊ธฐ๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ Handler ์„ค์ •
.failureHandler(oAuth2LoginFailureHandler) // ์†Œ์…œ ๋กœ๊ทธ์ธ ์‹คํŒจ ์‹œ ํ•ธ๋“ค๋Ÿฌ ์„ค์ •
.userInfoEndpoint().userService(customOAuth2UserService) // customUserService ์„ค์ •
.and()
.apply(new JwtSecurityConfig(tokenProvider, redisTemplate, jwtExceptionFilter));
.permitAll();
//JwtFilter ๋ฅผ addFilterBefore ๋กœ ๋“ฑ๋กํ–ˆ๋˜ JwtSecurityConfig ํด๋ž˜์Šค๋ฅผ ์ ์šฉ
http.apply(new JwtSecurityConfig(tokenProvider, redisTemplate, jwtExceptionFilter));

return http.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.sophy.sophy.config.auth.common;

import java.util.Collections;
import lombok.RequiredArgsConstructor;
import org.sophy.sophy.config.auth.CustomOAuth2User;
import org.sophy.sophy.config.auth.dto.OAuthAttributes;
import org.sophy.sophy.domain.Member;
import org.sophy.sophy.infrastructure.MemberRepository;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {

private final MemberRepository memberRepository;

@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
/**
* DefaultOAuth2UserService ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ, loadUser(userRequest)๋ฅผ ํ†ตํ•ด DefaultOAuth2User ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ ํ›„ ๋ฐ˜ํ™˜
* DefaultOAuth2UserService์˜ loadUser()๋Š” ์†Œ์…œ ๋กœ๊ทธ์ธ API์˜ ์‚ฌ์šฉ์ž ์ •๋ณด ์ œ๊ณต URI๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด์„œ
* ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์–ป์€ ํ›„, ์ด๋ฅผ ํ†ตํ•ด DefaultOAuth2User ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ ํ›„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
* ๊ฒฐ๊ณผ์ ์œผ๋กœ, OAuth2User๋Š” OAuth ์„œ๋น„์Šค์—์„œ ๊ฐ€์ ธ์˜จ ์œ ์ € ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ์œ ์ €
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadUser ํ•จ์ˆ˜๊ฐ€ ์†Œ์…œ๋กœ๊ทธ์ธ ํ–ˆ์„ ๋•Œ ์œ ์ €์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ ์ด ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ์ ์ด ์–ธ์ œ์ธ๊ฐ€์š”,,?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

์‚ฌ์šฉ์ž๊ฐ€ ์†Œ์…œ๋กœ๊ทธ์ธ ์‹œ๋„ -> ๊ตฌ๊ธ€ Authentication ์„œ๋ฒ„๋กœ Redirect -> ์‚ฌ์šฉ์ž ์ •๋ณด ์ œ๊ณต ๋™์˜ -> ์šฐ๋ฆฌ ์„œ๋ฒ„์— ์ธ์ฆ์ฝ”๋“œ ๋ฐœ๊ธ‰ -> ์ธ์ฆ์ฝ”๋“œ๋กœ ๊ตฌ๊ธ€ Authentication ์„œ๋ฒ„์— access token ๋ฐœ๊ธ‰ ์š”์ฒญ -> ๋ฐ›์€ access token์œผ๋กœ ๊ตฌ๊ธ€ Resourse ์„œ๋ฒ„์— ์‚ฌ์šฉ์ž ์ •๋ณด ์š”์ฒญ

์—ฌ๊ธฐ์„œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ loadUser ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
ํ˜„์žฌ ์ด ์ฝ”๋“œ์—์„  ์†Œ์…œ ๋กœ๊ทธ์ธํ•œ ์œ ์ €๊ฐ€ ์šฐ๋ฆฌ ์„œ๋น„์Šค์˜ ํšŒ์›์ธ์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•˜๊ณ  ์žˆ๊ณ , ์—ฌ๊ธฐ์„œ ๋ฐ˜ํ™˜๋˜๋Š” OAuth2User ๊ฐ์ฒด๋Š” ์Šคํ”„๋ง ์„ธ์…˜์— ์ €์žฅ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค~

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

์˜ค ๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋‹ˆ๊นŒ ์™„์ „ ์ž˜ ์ดํ•ด๋์Šต๋‹ˆ๋‹ค!๐Ÿ‘

OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest); // OAuth2 ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

//ํ˜„์žฌ ๋กœ๊ทธ์ธ ์ง„ํ–‰ ์ค‘์ธ ์„œ๋น„์Šค๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ์ฝ”๋“œ (๊ตฌ๊ธ€ or ๋„ค์ด๋ฒ„ or ์นด์นด์˜ค ...)
String registrationId = userRequest.getClientRegistration().getRegistrationId();
//OAuth2 ๋กœ๊ทธ์ธ ์ง„ํ–‰ ์‹œ ํ‚ค๊ฐ€๋˜๋Š” ํ•„๋“œ ๊ฐ’, Primary Key์™€ ๊ฐ™์€ ์˜๋ฏธ
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails()
.getUserInfoEndpoint().getUserNameAttributeName();

//OAuth2UserService๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์˜จ OAuth2User์˜ attribute๋ฅผ ๋‹ด์„ ํด๋ž˜์Šค
// ์†Œ์…œ ๋กœ๊ทธ์ธ์—์„œ API๊ฐ€ ์ œ๊ณตํ•˜๋Š” userInfo์˜ Json ๊ฐ’(์œ ์ € ์ •๋ณด๋“ค)
OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName,
oAuth2User.getAttributes());

Member member = getMember(attributes);

return new CustomOAuth2User(
Collections.singleton(new SimpleGrantedAuthority(member.getAuthority().getKey())),
oAuth2User.getAttributes(),
attributes.getNameAttributeKey(),
member.getEmail(),
member.getAuthority()
);
}

private Member getMember(OAuthAttributes attributes) {
Member findMember = memberRepository.findBySocialId(
attributes.getOAuth2UserInfo().getId()).orElse(null);

if (findMember == null) {
return saveMember(attributes);
}
return findMember;
}

/**
* ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ด๋ผ๋ฉด ์ด๋ฆ„๊ณผ ํ”„๋กœํ•„์ด๋ฏธ์ง€๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์ค๋‹ˆ๋‹ค.
* ์ฒ˜์Œ ๊ฐ€์ž…ํ•˜๋Š” ํšŒ์›์ด๋ผ๋ฉด Member ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. (์†Œ์…œ ํšŒ์›๊ฐ€์ž…)
**/
private Member saveMember(OAuthAttributes attributes) {
//๊ธฐ์กด ์œ ์ €๋„ ์ด๋ฉ”์ผ ์ธ์ฆ์„ ํ–ˆ๊ธฐ์—, ๋‘˜์ด ์ด๋ฉ”์ผ์ด ๊ฐ™์œผ๋ฉด ๊ฐ™์€ ์œ ์ €์ž„
// update๋Š” ๊ธฐ์กด ์œ ์ €์˜ ์†Œ์…œ ID ์ปฌ๋Ÿผ์— ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ ์ •๋„๋งŒ ์žˆ์œผ๋ฉด ๋ ๋“ฏ
Member member = attributes.toEntity(attributes.getOAuth2UserInfo());
return memberRepository.save(member);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.sophy.sophy.config.auth.common;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class OAuth2LoginFailureHandler implements AuthenticationFailureHandler {

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("์†Œ์…œ ๋กœ๊ทธ์ธ์ด ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค.");
log.error("์†Œ์…œ ๋กœ๊ทธ์ธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์—๋Ÿฌ๋ฉ”์„ธ์ง€ : {}", exception.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.sophy.sophy.config.auth.common;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.sophy.sophy.common.dto.ApiResponseDto;
import org.sophy.sophy.config.auth.CustomOAuth2User;
import org.sophy.sophy.controller.dto.response.TokenDto;
import org.sophy.sophy.domain.Member;
import org.sophy.sophy.domain.enumerate.Authority;
import org.sophy.sophy.exception.SuccessStatus;
import org.sophy.sophy.infrastructure.MemberRepository;
import org.sophy.sophy.jwt.TokenProvider;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Component
@RequiredArgsConstructor
public class OAuth2LoginSuccessHandler implements AuthenticationSuccessHandler {

private final TokenProvider tokenProvider;
private final MemberRepository memberRepository;
private final RedisTemplate redisTemplate;
private final ObjectMapper mapper = new ObjectMapper();

@Override
@Transactional
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
CustomOAuth2User customOAuth2User = (CustomOAuth2User) authentication.getPrincipal();

// User์˜ Role์ด GUEST์ผ ๊ฒฝ์šฐ ์ฒ˜์Œ ์š”์ฒญํ•œ ํšŒ์›์ด๋ฏ€๋กœ ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
if(customOAuth2User.getAuthority() == Authority.GUEST) {
response.sendRedirect("/auth/signup"); // ํ”„๋ก ํŠธ์˜ ํšŒ์›๊ฐ€์ž… ์ถ”๊ฐ€ ์ •๋ณด ์ž…๋ ฅ ํผ์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ (์ถ”๊ฐ€ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ค๊ณ  ๊ฑฐ๊ธฐ์„œ post ํ•ด์•ผ์ง€ User๋กœ ๋ฐ”๋€Œ๊ฒŒ ํ•ด์•ผ๊ฒ ๋‹ค)

//์•„๋ž˜์˜ GUEST๋ฅผ USER๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ๋กœ์ง์€ ํšŒ์›๊ฐ€์ž… ์Šน์ธ๋˜๋ฉด์„œ ์ฒ˜๋ฆฌ๋˜๊ฒŒ ๋ณ€๊ฒฝ
Member findUser = memberRepository.getMemberByEmail(customOAuth2User.getEmail());
findUser.authorizeUser();
} else {
TokenDto tokenDto = tokenProvider.generateTokenDto(authentication);
redisTemplate.opsForValue().set("RT:" + authentication.getName(),
tokenDto.getRefreshToken(),
tokenProvider.getRefreshTokenExpireTime(),
TimeUnit.MILLISECONDS);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().write(mapper.writeValueAsString(
ApiResponseDto.success(SuccessStatus.LOGIN_SUCCESS,
tokenDto)
));
// ๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ access, refresh ํ† ํฐ ์ƒ์„ฑ
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.sophy.sophy.config.auth.dto;

import java.util.Map;

public class GoogleOAuth2UserInfo extends OAuth2UserInfo{

public GoogleOAuth2UserInfo(Map<String, Object> attributes) {
super(attributes);
}

@Override
public String getId() {
return (String) attributes.get("sub");
}

@Override
public String getNickname() {
return (String) attributes.get("name");

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.sophy.sophy.config.auth.dto;

import java.util.Map;

public class KakaoOAuth2UserInfo extends OAuth2UserInfo{

public KakaoOAuth2UserInfo(Map<String, Object> attributes) {
super(attributes);
}

@Override
public String getId() {
return String.valueOf(attributes.get("id"));
}

@Override
public String getNickname() {
Map<String, Object> account = (Map<String, Object>) attributes.get("kakao_account");
Map<String, Object> profile = (Map<String, Object>) account.get("profile");

if (profile == null) {
return null;
}

return (String) profile.get("nickname");
}
}
Loading