스프링 시큐리티와 OAuth2.0으로 로그인 기능 구현하기

박일한·2021년 11월 16일
0

스프링 시큐리티

스프링에서 제공하는 인증과 인가(권한부여)기능을 가진 프레임워크이다.
스프링 기반의 에플리케이션에서 보안을 위한 표준이라고 생각하면 된다.

로그인

실무에서는 스프링시큐리티를 사용하지않고 별도의 로그인을 구현하고 암호화를 하였다.
MES라 일반적인 로그인 회원가입이 아니다 보니.. 커스텀으로밖에 갈수가 없다.
하지만 불특정 다수가 사용하는 프로그램(웹/앱)에서는 구글이나 네이버, 카카오등 SNS에서 제공하는 로그인 연동을 많이 사용한다.
로그인 구현자체에도 손이 많이가고 별도로 입력받는걸 좋아하지도 않는다.
(로그인 보안, 회원가입인증, 비밀번호, 아이디 찾기 등등 무수히 많다)

스프링부트 1.5와 2.0

책에서 보면 설정방법이 크게 바뀌었다고 나온다.
그이유는 spring-security-oauth2-autoconfigure 라이브러리에 의하여 발생되었다.
책에서 2.0을 권장하는 이유
1. 스프링팀에서 spring-security-oauth 프로젝트는 유지상태로 결정, 신규 기능 추가 없음
2. 스프링 부트용 라이브러리 출시
3. 확장 포인트가 적절하게 오픈되지않아 직접 상속하거나 오버라이딩 해야 하고 신규 라이브러리의 경우 확장 포인트를 고려해서 설계된 상태

그리고 1.5에서는 인증정보 뿐만아니라 url주소를 모두 명시해야지 사용 가능했지만
2.0에서부터는 인증정보만 있으면 사용이 가능하다.
이유는 CommonOAuth2Provider라는 enum이 추가되어 기본 설정값들을 모두 제공하기 때문이다.

구글 서비스등록

책에서는 구글과 네이버가 소개되어 있다.
구글 로그인을 해보자
구글에 구글 클라우드 플랫폼 또는 직접 https://console.cloud.google.com을 입력하면 된다.
만약 구글 클라우드 플랫폼을 검색해서 들어갔다면 콘솔을 클릭한다.
1. 프로젝트를 선택한다. 프로젝트가 없을시 프로젝트 선택이라고 나온다.

2. 신규 프로젝트를 생성한다.

새 프로젝트를 클릭하면 별도의 프로젝트를 등록 할 수 있는 창이 나온다.


프로젝트 이름을 입력하고 만들기 를 누르면 프로젝트가 생성된다.
3. 사용자 인증정보 만들기
1) 좌측의 사이드바에서 api서비스 -> 대시보드를 클릭한다.

2) 좌측의 사이드바에서 사용자 인증정보를 클릭한다.

3) 사용자 인증정보 만들기를 클릭한다.

4) Oauth 클라이언트 Id를클릭한다.
5) Oauth 클라이언트 내용 입력

해당 내용을 입력하고 만들기를 누르면 ID가 만들어 진다.
중요포인트 : 승인된 리디렉션 URL : http://localhost:8080/login/oauth2/code/google
을 입력해야한다.

승인된 리디렉션 URL

  1. 서비스에서 파라미터로 인증 정보를 주었을때 인증이 성공하면 구글에서 리다이렉트할 URL이다.
  2. 스프링부트 2버전에서는 기본적으로 {도메인}/login/oauth2/code/{소셜서비스코드}로 지원
  3. 사용자가 별도로 리다이렉트 URL을 지원하는 Controller가 필요없다.

프로젝트에 구글인증정보 등록

application.properties가 아닌 인증정보 properties를 별도로 작성한다.
application properties가 있는곳에 application-oauth.properties를 작성한다.

중요포인트 : scope=profile,email
1) 기본 인증값은 openid, profile, email
2) 강제로 profile, email을 등록 한 이유는 openid라는 scope가 있으면 openid provider로 인식하기 때문이다.
3) openId Provider인 서비스와 그렇지 않은 서비스로 나눠서 각각 Oauth2Service를 만들어야한다.
4) 하나의 Oauth2Service를 사용하기위해 일부러 openid를 빼고 등록한다.
이제 application.properties에 위에 만든 파일을 연동시킨다.

스프링 부트에서는 application-xxx.properties로 만들면 xxx이라는 이름의 profile이 생성되어 이를 관리 할 수있다.
즉 profile=xxx라는 식으로 후출하면 해당 properties의 설정들을 가져올 수 있다.

.gitignore 등록

oauth.properties 파일은 보안이 중요한 정보라서 git에 노출되면 안된다.
그리서 gitignore 파일에
application-oauth.properties를 입력해준다.
인텔리제이로 파일을 만들때 무심코 add를 누르면 자동으로 add가 된 상태가 된다.
이러면 gitignore를 해도 파일이 올라가게 된다.

구글 로그인 연동하기

  1. User클래스 작성

    여기서 중요포인트 : Role이다.
    스프링 시큐리티를 연동하려면 역할이 필요하다. 그리고 항상 ROLE_을 앞에 붙여야 한다.

    이런식으로 규칙을 정하여 구분하여 접근제어를 할 수있다.
    Enum에서 type을 정할 수 있는데
    EnumType.ORDINAL : int형으로 순번을 저장
    EnumType.String : String형으로 문자로 저장
    당연히 String으로 사용하게 편하지 않을까 생각한다.
    그리고 Ordinal의 문제점이 있는데 추가내용이 중간에 들어가거나 했을경우, 순번이 변경이 되버린다. 그러면 기존에 있던 데이터들도 변경이 된다는 뜻이다.
  2. Repository 등록
    소셜 로그인으로 반환되는 값중 email을 통해 이미 생성된 사용자인지 처음 가입하는 사용자인지 판단하기 위한 메서드를 작성한다.

스프링 시큐리티 설정

  1. build.gradle에 의존성 추가(implementation 'org.springframework.boot:spring-boot-starter-oauth2-client')
  • 소셜 로그인등 클라이언트 입장에서 소셜 기능 구현시 필요한 의존성 이다.
    2.별도의 패키지를 만들어 시큐리티 관련 클래스를 구현한다.

Security Config


@EnableWebSecurity : SpringSecurityFilterChain이 자동으로 포함(설정 활성화)
WebSecurityConfigurerAdapter를 상속받아 오버라이딩 하는 방식으로 구현
anyMatchers : 권한관리 대상을 지정하는 옵션이다.

CustomOAuth2UserService


registrationId : 로그인 진행중인 서비스를 구분
userNameAttributeName : OAuth2로그인 진행 시 키가 되는 필드값(Pk)
OAuthAttributes : OAuth2UserService를 통해 가져온 OAuth2User의 attribute를 담을 클래스
sessionUser : 세션에 사용자 정보를 저장하기 위한 Dto클래스
SNS 로그인을 진행시 체크되는 부분이며 로그인이 성공 하였을때 OAuth정보가 생성된다.
OAuth정보에 email을 기준으로 사용자 테이블을 조회하여 일치여부를 확인 후 정보가 없을시 Guest로 있을시 해당 정보를 가져온다.
여기서 정보를 가져왔을때 이름이나 프로필 사진이 변경되면 User엔티티에도 update가 실행된다.

OAuthAtrributes



SNS의 로그인시 받아오는 정보들의 Dto이다.
SNS별 별도의 메서드가 필요하다.(받아오는 체계가 다르기 때문이다.)

SessionUser


인증된 사용자 정보만 필요하다. entity는 기본적으로 접근하지않는다.
그리고 sessionUser를 작성할땐 serialize를 통하여 직렬화를 한다.
직렬화란 간단하게 얘기해서 데이터를 묶어 준다고 보면 되는데
자바 시스템에서 사용되는 Object나 Data를 외부에서도 사용 할 수 있도록 Byte형태로 데이터를 변환하는 기술을 말한다.

Controller


여기서 특별한 것은 @LoginUser라는 어노테이션이다.
해당 어노테이션은 별도로 사용하여 불필요한 HttpSession 인터페이스를 사용하지 않는것이다.

LoginUser


@Interface를 이용하여 이 파일을 어노테이션 클래스로 지정한다.

LoginUserArgumentResolver


supportsParameter를 이용하여 컨트롤러 메서드의 특정 파라미터를 지원하는지 판단
@Component를 이용하여 스캔될수 있도록 하였다.

로그인 결과


로그인이 잘 되었다.
근데 하다보니 버그가 발생되었었다.
머스테치에서 UserName을 사용한것이 윈도우10 사용자 이름과 충돌이 난것이다.
그래서 난 UserName을 GuestName으로 바꾸어 사용하였다.
하지만 내가 로그인한 것은 Guest이기 때문에 글쓰기나 이런것들은 되지 않는다.
강제로 DB에서 User로 바꿔줘야지만 가능하다.

네이버 로그인 연동하기

네이버 개발자 센터를 검색하거나 https://developers.naver.com/apps/#/register?api=nvlogin으로 접속하면된다.

해당 내용들을 입력한후 등록하기를 하면 애플리케이션이 등록된다.

추가로 서비스URL과 네이버아이디 로그인 URL을 입력한다.

그럼해당과 값이 어플리케이션 정보가 나타난다.

application-OAuth

구글과 마찬가지로 해당 등록 인증정보가 필요하다. 하지만 구글과는 달리 지원이 안되기 때문에
작성에해되는 부분이 많다.

구글은 3줄이면 되던것이 10줄로 변경되었다.
이제 구글에서 똑같이 attribute를 작서앻여되는데 해당코드는 위에 존재한다.
여기서 다시 언급하자면
구글은 Attributes에서 바로 꺼낼 수 있지만
네이버는 response를 다시 꺼내서 사용을 해야한다.

네이버의 API구조가 아래의 구조이기 때문이다.

테스트코드 실패

기존 테스트에 시큐리티 적용으로 문제가 되는부분들이 많았다.
전체 테스트하는방법
gradle -> tasks -> verification -> test를 하면 전체 테스트를 수행한다.
1. CustomOauth2UserService를 찾을 수 없음.
customOauth2UserService를 생성하는데 필요한 소셜 로그인 관련 설정값이 없기 때문이다.
그래서 main에 있는 application.properties를 test에도 똑같이복사해주었다.

2. Status Code
인증되지 않은 사용자의 요청이 발생된다. 그래서 스프링 시큐리티 테스트를 위한 여러 도구를 지원하는 spring-security-test를 build.gradle에 의존성을 주입 시킨다.

해당 인증된 모의 사용자를만들어 테스트를 진행하면 동작을 한다.

위의 이미지는 mockMvc사용법이다.
3. @WebMvcTest에서 CustomOauth2UserService를 찾을 수 없음.
webMvcTest는 해당 service를 스캔하지 않는다.
즉 repository, service, component는 스캔 대상이 아니다.
따라서 seuciryConfig를 스캔하지 않도록 변경한다.

4. EnableJpaAuditing
enableJpaAuditing을 사용하려면 최소 하나의 entitiy가 필요한데 webMvcTest에는 없기때문에 에러가 발생했다.
application.class를 보면 EnableJpaAuditing, SpringBootApplication이 같이 있기때문에 둘다스캔이 된것이다.
그래서 해결방법은 enableJpaAuditing을 별도로 분리하는 것이다.

이번 챕터의 나의 생각

스프링 시큐리티를 실무에서 많이 다루지도 않았고 직접 책을 보면서 설정을 해도 정말 어렵다고 생각한다.
기존에 JPA를 공부하면서 설정했던 방법과는 또 다르긴하지만 기본적은 메타정보는 같기때문에
설정하는 방법이나 이런것들을 잘봐야겠다.
그리고 요즘은 거의 소셜 로그인을 많이 이용하기 때문에 나중에 카카오나 다른 소셜로그인도 추가로 구현해보는것이 좋을것 같다. 이미 구현을 해보고 글을 쓰려니 더 힘든것 같다.
구현을 해보면서 작성해 나가면 그때 당시의 문제점도 자세히 서술할수 있을텐데..아쉽다.

profile
긍정적인 삶을 갖자~~

0개의 댓글