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: Add 쇼핑몰 API 테스트코드 추가 #22

Open
wants to merge 25 commits into
base: sujin
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f038a87
feat: Delete 원래 실습코드파일(ServerStudyPractice) 삭제
suucong Oct 1, 2023
199c0c9
feat: Add 스테이징 되지 않은 파일들 추가
suucong Oct 1, 2023
74a85c9
Committing local changes before pulling
suucong Oct 1, 2023
3bf9ace
Committing changes in Application.java
suucong Oct 1, 2023
eaf9bd0
feat: Add .gitignore파일 추가
suucong Oct 1, 2023
7b48dcc
feat Add: 책 CH4까지 구현하고, 테스트코드 제외한 과제코드 추가
suucong Oct 6, 2023
6949bf6
chore: Update .gitignore파일에 .idea파일 수정해서 추가
suucong Oct 6, 2023
7661e10
chore: Update .gitignore파일에 .idea파일 수정해서 추가
suucong Oct 6, 2023
febd85d
feat: Add 쇼핑몰 API 테스트코드 추가
suucong Oct 9, 2023
547969f
chore: Modify junit 버전 변경
suucong Nov 5, 2023
9332883
chore: Modify clear git cache
suucong Nov 5, 2023
7c850d2
chore: Add application-oauth.properties to .gitignre
suucong Nov 11, 2023
601e68a
chore: Add application-oauth.properties to application.properties
suucong Nov 11, 2023
c762a0d
feat: Add User Entity
suucong Nov 11, 2023
7ac332d
feat: Add Role
suucong Nov 11, 2023
90559dc
feat: Add UserRepository
suucong Nov 11, 2023
a6cb605
feat: Add SecurityConfig
suucong Nov 11, 2023
e7192cd
feat: Add CustomOAuth2UserService
suucong Nov 11, 2023
ad3c748
OAuthAttributes
suucong Nov 11, 2023
86959e1
chore: Revert prior commit
suucong Nov 11, 2023
a163b13
feat: Add CustomOAuth2UserService
suucong Nov 11, 2023
7ea3dff
feat: Add SessionUser
suucong Nov 11, 2023
0ee5639
feat: Add LoginUser
suucong Nov 11, 2023
008a486
feat: Add CH5 LoginUser Custom Annotation 까지
suucong Nov 11, 2023
064362e
feat: Add CH5 Code
suucong Nov 28, 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
Binary file removed .DS_Store
Binary file not shown.
1 change: 0 additions & 1 deletion .gitattributes.txt

This file was deleted.

6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
### IntelliJ IDEA ###
/.idea/
### Mac OS ###
.DS_Store
### OAuth ###
application-oauth.properties
8 changes: 0 additions & 8 deletions ServerStudyPractice/.idea/.gitignore

This file was deleted.

17 changes: 0 additions & 17 deletions ServerStudyPractice/.idea/gradle.xml

This file was deleted.

10 changes: 0 additions & 10 deletions ServerStudyPractice/.idea/misc.xml

This file was deleted.

39 changes: 0 additions & 39 deletions ServerStudyPractice/build.gradle

This file was deleted.

2 changes: 0 additions & 2 deletions ServerStudyPractice/settings.gradle

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@ bin/
.vscode/

### Mac OS ###
.DS_Store
.DS_Store

### OAuth ###
application-oauth.properties
37 changes: 37 additions & 0 deletions suucong/SpringBoot/SpringBootPractice/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.15'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
sourceCompatibility = '11'
}

repositories {
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-mustache'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.projectlombok:lombok:1.18.22'
testImplementation 'org.testng:testng:7.1.0'
testImplementation 'junit:junit:4.13.1'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.h2database:h2'
implementation('org.springframework.boot:spring-boot-starter-mustache')
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.session:spring-session-jdbc'
annotationProcessor'org.projectlombok:lombok'
testImplementation('org.springframework.security:spring-security-test')
}

tasks.named('test') {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Sun Sep 17 21:41:43 KST 2023
#Mon Oct 02 08:27:41 KST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 2 additions & 0 deletions suucong/SpringBoot/SpringBootPractice/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rootProject.name = 'SpringBootPractice'

Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.sujin.book.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing // JPA Auditing 어노테이션을 모두 활성화 할 수 있도록 함.
@SpringBootApplication // 스프링부트의 자동 설정, 스프링 Bean 읽기와 생성을 모두 자동으로 설정. 이 어노테이션이 있는 위치부터 설정을 읽어가기 떄문에 이 클래스는 항상 프로젝트 최상단에 위치해야함.
public class Application {
public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.sujin.book.springboot.config.auth;

import com.sujin.book.springboot.config.auth.dto.OAuthAttributes;
import com.sujin.book.springboot.config.auth.dto.SessionUser;
import com.sujin.book.springboot.domain.user.User;
import com.sujin.book.springboot.domain.user.UserRepository;
import lombok.RequiredArgsConstructor;
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.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.util.Collections;

@RequiredArgsConstructor
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final UserRepository userRepository;
private final HttpSession httpSession;

@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest);

String registrationId = userRequest.getClientRegistration().getRegistrationId();
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();

OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName, oAuth2User.getAttributes());

User user = saveOrUpdate(attributes);
httpSession.setAttribute("user", new SessionUser(user));

return new DefaultOAuth2User(
Collections.singleton(new
SimpleGrantedAuthority(user.getRoleKey())),
attributes.getAttributes(),
attributes.getNameAttributeKey());
}

private User saveOrUpdate(OAuthAttributes attributes) {
User user = userRepository.findByEmail(attributes.getEmail())
.map(entity -> entity.update(attributes.getName(), attributes.getPicture()))
.orElse(attributes.toEntity());

return userRepository.save(user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.sujin.book.springboot.config.auth;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.sujin.book.springboot.config.auth;

import lombok.RequiredArgsConstructor;
import com.sujin.book.springboot.domain.user.Role;
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.configuration.WebSecurityConfigurerAdapter;

@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;

@Override
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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.sujin.book.springboot.config.auth.dto;

import com.sujin.book.springboot.domain.user.Role;
import com.sujin.book.springboot.domain.user.User;
import lombok.Builder;
import lombok.Getter;

import java.util.Map;

@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;
}

public static OAuthAttributes of(String registrationId, String userNameAttributeName, Map<String, Object> attributes) {
return ofGoogle(userNameAttributeName, attributes);
}

private 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();
}

public User toEntity() {
return User.builder()
.name(name)
.email(email)
.picture(picture)
.role(Role.GUEST)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.sujin.book.springboot.config.auth.dto;

import com.sujin.book.springboot.domain.user.User;
import lombok.Getter;

import java.io.Serializable;

@Getter
public class SessionUser implements 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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.sujin.book.springboot.domain;

import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)

public abstract class BaseTimeEntity {
@CreatedDate
private LocalDateTime createdDate;

@LastModifiedDate
private LocalDateTime modifiedDate;
}
Loading