프로젝트에 참고한 책: '스프링 부트와 AWS로 혼자 구현하는 웹 서비스'

ec2에 배포하기에 앞서 ec2서버를 만들고, rds도 만들어야한다. 만드는 법은 다음 링크를 참조하면 된다

배포를 다 한후 기록용으로 남기는 내용이라 일부 부족한 내용이 있을 수 있다. 그런 경우는 책 내용을 찾아보는 것을 추천한다 

 

-ec2 인스턴스 생성: https://victorydntmd.tistory.com/61

-rds 데이터베이스 생성: https://zamezzz.tistory.com/302

이부분 도 역시 추가로 공부할 부분이 있다면 책을 통해 공부하는 것을 추천

 

이제 본격적으로 배포를 해보자 

먼저 github에 있는 코드들을 ec2에 불러와야한다.

1. EC2에 깃 설치

2. 깃버전 확인

3.프로젝트를 저장할 디렉토리 생성

4. 생성한 디렉토리로 이동

5. 깃 클론하기

6. 파일 잘 복사되었는지 확인한다

7. 코드 잘 수행되는지 테스트를 진행한다

되도록이면 테스트에 오류가 없는게 좋으므로 미리 IDE에서 통합 테스트 진행 후 완료된 상태에 하면 좋을 것 같다

8. 테스트 실패 시 코드 수정 후 재 push했을 때

-git pull 입력

-만약 다음과 같이 gradlew 실행 권한이 없다는 메시지가 뜬다면

=> -bash: ./gradlew: Permission denied

chmod +x ./graldew 명령어로 실행권한을 추가한 뒤 다시 테스트를 수행하면 된다

 

이렇게 ec2에 프로젝트를 클론하는 것을 완료하였다 

 

프로젝트에 참고한 책: '스프링 부트와 AWS로 혼자 구현하는 웹 서비스'

코드에서 같은 부분이 반복된다면 수정시 반복되는 모든 부분을 찾아 수정을 해야하는 상황이 발생할 수 있다. 

따라서 이 프로젝트에서 개선해야하는 부분을 찾아서 개선하려고 한다 

-프로젝트에서 개선해야할 부분()

해당 코드는 IndexController에 있는 Index()메소드의 코드인데, index 메소드 외에 다른 컨트롤러와 메소드에서 세션값이 필요하면 그때마다 직접 세션에서 값을 가져와야한다. 따라서 이부분을 개선할 @LoginUser 어노테이션을 만들어보도록 하자

1. @LoginUser

config/auth 패키지에 해당 어노테이션을 작성한다

코드작성은 간단하다 

 

2. LoginUserArgumentResolver

@LoginUser 어노테이션이 기능할 수 있도록 해당 클래스를 같은 패키지에(config/auth) 생성한다 

이는 HandlerMethodArgumentResolver라는 인터페이스를 구현한 클래스이다

HandlerMethodArgumentResolver는 한 가지 기능을 지원하는데, 해당 구현체가 지정한 값으로 해당 메소드의 파라미터로 넘길 수 있다

 

 

-supportParameter()

컨트롤러 메소드의 특정 파라미터를 지원하는지 판단한다

첫째로 파라미터에 @LoginUser 어노테이션이 붙어 있고, 

두번째로 파라미터 클래스 타입이 SessionUser.class인 경우 true를 반환한다 

예를 들면 (@LoginUser SessionUser user)인 경우 기능한다

 

-resolveArgument

파라미터에 전달할 객체를 생성한다

세션에서 객체를 가져온다

 

3. WebConfig

LoginUserArgumentResolver가 스프링에서 인식될 수 있도록 WebMvcConfigurere에 추가하는 과정이다

config패키지에 WebConfig를 생성한다 

 

모든 과정이 끝났다면 @LoginUser 어노테이션으로 코드를 개선하면 된다 

 

개선 전 코드

개선 후 코드 

프로젝트에 참고한 책: '스프링 부트와 AWS로 혼자 구현하는 웹 서비스'

 

로그인 관련 정보를 전달해주는 dto는 두가지가 있다.

하나는 OAuthAttributes이고, 다른 하나는 SessionUser이다

 

1. OAuthAttributes

 

필드 선언(attributes, nameAttributeKey 추가 되었다)

 

OAuthAttributes 필드가지고 생성자 생성하기 

 

of() 메소드 선언 

registrationId가 naver라면 ofNaver()를 반환하고, naver가 아니면 ofGoogle()로 반환한다 

 

ofGoogle()은 attributes에서 name,email,picture가져오고, attributes에서 attributes가져오고(?), userNameAttributeName에사 nameAttributeKey 가져온다(?)

ofNaver()는 먼저 response 객체를 생성한다

resonse에서 name,email,profile_image,attributes를 가져온다

마지막으로 userNameAttributeName에서 nameAttributeKey를 가져온다(?) 모르겐네,,,

 

-of(): OAuth2User에서 반환하는 사용자 정보는 Map이기 때문에 값 하나하나를 반환해야 한다

 

주어진 이름,이메일,사진,권한으로 User 엔티티 생성한다

-toEntity(): User 엔티티를 생성한다.

OAuthAttributes에서 엔티티를 처음 생성하는 시점은 처음 가입할 때이므로, GUEST 권한을 준다.

guest 권한을 주기 위해 role(Role.GUEST)를 사용한다 

 

2.SessionUser

이는 세션에 인증된 사용자 정보를 저장하기위해 사용하는 dto 클래스이다

user클래스를 쓰지 않고 따로 만든 이유는 직렬화 기능을 보장하기 위해서이다

user는 entity 클래스이므로 다른 엔티티와 언제 연관관계를 맺을지 모르기 때문에 직렬화가 되어도 부수적인 오류가 발생할 수 있기 때문에 dto를 따로 만들어서 정보를 저장한다

코드는 비교적 간단하다 

 

Serializable(직렬화): 자바 시스템 내부에서 사용되는 Object 또는 Data를 외부의 자바 시스템에서도 사용할 수 있도록 byte 형태로 데이터를 변환하는 기술.

 

 

 

3. Index Controller

 

index.mustache에서 userName을 사용할 수 있게 IndexControlle에서 userName을 model에 저장하는 코드를 추가한다 

 

-(SessionUser) httpSession.getAttribute("user): 로그인 성공 시 httpSession.getAttribute("user")에서 값을 가져올 수 있다

-if(user !=null): 세션에 저장된 값이 있을 때만 model에 userName을 등록한다 

프로젝트에 참고한 책: '스프링 부트와 AWS로 혼자 구현하는 웹 서비스'

1. build.gralde에 의존성 추가하기

compile('org.springframework.boot:spring-boot-starter-oauth2-client')

로그인 관련 의존성 추가 

testCompile('org.springframework.security:spring-security-test')

스프링 시큐리티 의존성 추가

 

2. config/auth 패키지 생성 후 SecurityConfig 클래스 만들기 

 

@EnableWebSercurity: Spring Security 설정들을 활성화 시켜준다 

 

 

코드를 상세하게 분석해보려 한다 

1. 

h2-console 화면을 사용하기 위해 해당 옵션들을 disable 한다

 

2.

-authorizeRequests(): URL별 권한 관리를 설정하는 옵션의 시작점 .이게 선언되어야 antMatcher옵션을 사용할 수 있다 

-antMatchers(): 권한관리 대상을 지정하는 옵션이다. URL,HTTP 메소드 별로 관리가 가능하다

-antMatchers(~).permitAll(): ~에 지정된 URL들은 permitAll() 옵션을 통해 전체 열림권한을 주었다.(css,js있는 것으로 보아 모든 화면은 볼 수 있는 것 같다)

-antMatchers("/api/v1/**"): "/api/v1/**" 주소를 가진 API는 USER 권한을 가진 사람만 가능하도록 한다

-anyRequest(): 설정된 값들 이외 나머지 URL들을 나타낸다 

 

3.

.logout().logoutSuccessUrl("/): 로그아웃시 "/" URL로 이동한다 

 

4.

-oauth2Login(): OAuth2 로그인 기능에 대한 여러 설정의 진입점이다 

-userInfoEndpoint(): OAuth2 로그인 성공 이후 사용자 정보를 가져올 때의 설정을 담당한다

-userService(): 소셜 로그인 성공 시 후속 조치를 진행할 UserService 인터페이스의 구현체를 등록한다. 소셜 서비스들에서 사용자 정보를 가져온 상태에서 추가로 진행하고자 하는 기능을 명시할 수 있다

 

3. CustomOAuth2UserService

구글 로그인 이후 갖온 사용자의 정보(email.name,picture etc)들을 기반으로 가입 및 정보수정, 세션 저장 등의 기능을 지원하는 클래스이다.

여기는 몇번을 봐도 잘 모르겠다,, 로그인 부분 중 가장 어려운 부분. 언젠가 이해가 오는 날이 오겠지?

 

 

loadUser() 코드를 상세하게 분석해 본다

 

 

1.

delegate 뜻이 대리인이던데, 아마 무언가를 대리하는 객체인 것 같다. OAuth2UserService<OAuth2UserRequest, OAuthUser>는 implementation한 인터페이스인 것 같다 

oAuth2User를 delegate에서 useRequest를 가지고 loadUser를 가져온건가(?) 

 

2.

-registrationId :현재 로그인 진행중인 서비스를 구분하는 코드이다(구글을 이용하면 구글, 네이버를 이용하면 네이버를 가리킨다)

 

3.

-userNameAttributeName: OAuth2 로그인 진행 시 키가 되는 필드값을 이야기 한다. PrimaryKey와 같은 의미.

 

4.

 

-OAuthAttributes: OAuth2UserService를 통해 가져온 OAuth2User의 attribute를 담은 클래스이다.

다른 소셜 로그인도 이 클래스를 이용한다

-OAtuhAttributes.of(registrationId,userNameAttributeName,oAuth2User.getAttributes());

 

궁금한 점: attribute라고 하면 속성인데, 컬럼을 말하는건가?? 

 

5.

구한 attributes를 saveOrUpdate() 메소드로 user에 저장한다

httpsession.setAttribute()로 user의 사용자 정보를 세션에 저장한다 

 

6.

 

7.

+ Recent posts