프로젝트에 참고한 책: '스프링 부트와 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.

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

시작에 앞서 구현 순서를 정리해 보았다

1. 구글 서비스 등록

2.application.properties에 서비스 id,pw 등록

3.domain에서 user,role 클래스와 userRepository 생성

4. config/auth 패키지 만들어서 SecurityConfig, CustomOAuth2UserService 생성

5. config/auth/dto 패키지에 OAuthAttributes, SessionUser 생성

6. config/auth/dto 패키지에 LoginUser 어노테이션, LoginUserArgumentResolver 생성

7. config 패키지에 WebConfig 생성 

 

스프링 시큐리티란

막강한 인증(authentication)과 인가(authorization) 기능을 가진 프레임워크이다

로그인 기능은 스프링 시큐리티(spring security)를 이용해서 구현했다

 

최근에는 인터셉터,필터 기반의 보안 기능을 구현하는 것보다 스프링 시큐리티를 통해 구현하는 것을 권장하고 있다

이유는 확장이 용이해서 다양한 요구사항을 쉽게 추가하고 변경할 수 있다. 

 

본 초기 프로젝트에서는 내부 로그인 서비스를 개발하려고 했으나, 소셜 로그인 기능을 이용하는 것이 더 이익일 것 같아 

구글,네이버 로그인 기능을 이용했다 

 

자체 로그인 기능 개발시 개발해야하는 것들이 많다

예를 들면 로그인시 보안, 전화번호,이메일 인증, 비밀번호 찾기/변경, 회원정보 변경 등 

소셜 로그인을 하면 위 부분은 개발 안해도 되니 다른 기능에 초점을 두어 개발할 수 있다 

 

구글 로그인 구현 시작

1. 구글,네이버에 서비스 등록 

코드 위주로 기록을 할 것이기 때문에 등록 과정은 다음 링크를 참조하면 될 것 같다

구글: https://smpark1020.tistory.com/203

네이버: https://loosie.tistory.com/301 

 

위 과정을 통해서 등록을 했으면, 생성된 클라이언트 ID와 비밀번호를 main/main/java/resource 패키지에 application-oauth.properties 파일을 생성해서 다음과 같이 작성하면된다

 

 

oauth properties의 설정을 가져오기 위해서 application.properties에 spring.profiles.include=oauth

그리고 이 정보가 github에 push 되면 안되므로 git.ignore에  application-oauth.properties를 추가한다

 

2. User 클래스 생성

이것도 posts와 비슷하게 필드들 채워나가면 된다.

다른 점은 role이라는 필드가 생겼다는 점이다. 사용자가 처음 방문하면 Guest라는 권한으로 접근을 하게 되고, 한번 로그인한 기록이 있다면 User 권한을 부여해 서비스를 이용할 수 있게 하기위해 있는 것 같다

이는 Role enum클래스를 user 클래스와 같은 /domain/user 패키지에 생성하면된다

 

@Enumerated(Enum Type.STRING)에 대해서

JPA로 db에 저장할 때 enum값은 기본적으로 int값으로 저장되는데

숫자로 저장되면 db를 확인할 때 무슨 코드를 의미하는지 알 수가 없기 때문에 문자열로 저장하게 위한 어노테이션을 선언한다

 

자세한 user 클래스 코드는 다음 링크를 참조하면된다 

https://github.com/heyazoo1007/bookproject/blob/master/src/main/java/com/heyazoo1007/book/domain/user/User.java

entity 클래스 작성할 때 @builder로 생성자 작성하면 더 용이하다

해당 엔티티로 update 기능도 만든다면 update 생성자(?)도 만들어 놓아야한다

3. UserRepository 생성 

User의 CRUD를 책임지는 리포지토리도 posts와 같은 방식으로 하면되고 email로 찾는 것만 추가해주면 된다

 

4. Role 클래스 생성

 

스프링 시큐리티에서는 권한 코드에 항상 ROLE_이 있어야해서 붙여서 key를 작성했다 

Role(key:  , title:  ) 이므로 key와 title 필드를 final로 작성한다 

 

1.  로그인 구현 전에 주요 화면 작업 끝내기

-> 로그인 구현하고 화면 수정하니까 수정할 때마다 계속 로그인하고, user권한 부여한 뒤 책 등록 하고,, 너무 번거로웠다

 

2. 화면 구현 중에 delete 버튼을 꼭 수정완료 옆 버튼이 아닌 자유롭게 추가할 수 있는 방법을 좀 더 공부해야할 것 같다

 

3. 후기 작성 칸 늘리면서 review값 받아오는 거 찾아봐야할 것 같다 

 

+ Recent posts