2021 07 18
2021-07-18¶
생활코딩 OAuth¶
- 개요 - 사용자 -> 서비스 -> Google 캘린더에 기록 - 사용자의 id/pw를 받아서 서비스가 기록해주기 - 모두가 불행해지는 지름길 - OAuth를 통해 극복! - 사용자의 요청에 따라 accessToken을 Google이 발급해줌 - accessToken을 서비스가 넘겨받음 - accessToken을 사용하여 서비스가 Google이 허락한 범위 내에서 기능 처리 뚝딱
- 역할 - Resource Owner (user) - Client (서비스) - Resource Server (Google) - Authorization Server (인증 전담 서버) 포함
- 등록 - Client --[register]--> Resource Server - [register] - Client ID, Client Secret, Authorized redirect URIs (https://client/callback) - 구글님! 저 당신의 OAuth 서비스를 쓸려고 합니다. - 우리 서비스는 이런 이름을 가지고 있고, 이런 URL을 사용해요. - 인증 다 해주시고 https://client/callback으로 요청 주세요!
- Resource Owner의 승인 - 이제 Resource Owner가 우리 서비스 들어와서 구글로 로그인 하기 클릭했어 - 그러면 우리 서비스에서 구글에게 요청을 보내줘야해 - https://resource.server?client_id=1&scope=B,C&redirect_uri=https://client/callback - 발급 받은 client_id : 1 - 사용하고자 하는 기능 : B, C - 리다이렉트 할 URI : https://client/callback - 이제 Resource Owner가 구글에 로그인하면,,, - 구글에서 user_id = 1이, 기능 B,C에 대해 나의 서비스에서 접근 가능하도록 요청했다 기록
- Resource Server의 승인 - Resource Server는 Authorization_Code를 발급함 - Resource Owner에게 https://client/callback?code=Authorization_Code 로 리다이렉트 보내라고 지시 - Resource Owner는 자기도 모르게 우리 서비스에 해당 요청 보냄 - 이제 우리 서비스에서 Resource Server에 직접 접근한다! - https://resource.server/token?grant_type=authorization_code&code=3&redirect_uri=https://client/callback&client_id=1&client_secret=2 - 요청한 정보가 다 맞다면 이제 Access Token 발급해주자!
- Access Token - Resource Server랑 서비스에서 Authorization_Code를 지움! - Resource Server가 AccessToken 발급하고, 서비스에게 넘겨줌! - Access Token을 이제 HTTP 헤더 에다가 끼워서 넣어주세요~
- Refresh Token - Access Token은 수명이 있어! - 그래서 Resource Server가 처음에 Access Token이랑 Refresh Token을 같이 줘 - Access Token이 Invalid라면 Refresh Token으로 찔러서 새로운 Access Token 받아!
Spring RestDocs¶
- 참고: https://techblog.woowahan.com/2597/
- RestDocs vs Swagger - RestDocs 장점 - Production 코드 영향 X - 테스트 코드 성공 시 문서작성 완료 - RestDocs 단점 - 적용하기 어려움
- MockMvc vs RestAssured
- MockMvc를 통해
@WebMvcTest로 테스트 수행하자 - Controller Layer만 테스트함 - Spring RestDocs를 통해 문서 작성하기엔 MockMvc가 더 좋음
- build.gradle 살펴보기
- junit, MockMvc(
@WebMvcTeat), asciiDoc을 통해 최소한의 라이브러리로 문서화 제공 가능buildscript { ext { springBootVersion = '2.1.1.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot") } } plugins { id "org.asciidoctor.convert" version "1.5.9.2" // (1) AsciiDoc 파일 컨버팅하고, Build 폴더에 복사 } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 asciidoctor { dependsOn test // (2) gradle build 시 test -> asciidoctor 순으로 수행 } bootJar { dependsOn asciidoctor // (3) gradle build 시 asciidoctor -> bootJar 순으로 수행 from ("$/html5") { // (4) ./build/asciidoc/html5/에 html 파일 생성 into 'static/docs' // 이후 /static/docs/ 폴더에 복사가 됨 } } repositories { mavenCentral() } dependencies { implementation('org.springframework.boot:spring-boot-starter-web') implementation('org.springframework.boot:spring-boot-starter-data-jpa') implementation('org.projectlombok:lombok') runtimeOnly('com.h2database:h2') testImplementation('org.springframework.boot:spring-boot-starter-test') testImplementation('org.springframework.restdocs:spring-restdocs-mockmvc') // (5) }
- 기능 살펴보기
- getDocumentRequest() 로 호스트 이름을 바꿔주자!ㄴ
@ActiveProfiles("test") @AutoConfigureRestDocs @MockBean(JpaMetamodelMappingContext.class) public class ControllerTest { @Autowired private WebApplicationContext wac; @Autowired private RestDocumentationContextProvider restDocumentationContextProvider; @Autowired public ObjectMapper objectMapper; @MockBean public AuthService authService; public MockMvc mockMvc; @BeforeEach void setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(wac) .addFilters(new CharacterEncodingFilter("UTF-8", true)) .alwaysDo(print()) .apply(MockMvcRestDocumentation.documentationConfiguration( restDocumentationContextProvider )) .build(); } protected static OperationRequestPreprocessor getDocumentRequest() { return preprocessRequest( modifyUris() .scheme("https") .host("nolto.kro.kr") .removePort(), prettyPrint()); } protected static OperationResponsePreprocessor getDocumentResponse() { return preprocessResponse(prettyPrint()); } }
HTTP Redirect¶
- 참고 1: https://dololak.tistory.com/147
- 참고 2: https://mangkyu.tistory.com/51
- 리다이렉트란? - 웹서버는 HTTP 응답 상태코드를 302로 보내고, 헤더 중 Location 값으로 리다이렉트 되어야 할 주소 설정해 리턴
- Forward vs Redirect - Forward - 브라우저는 다른 페이지로 이동한지 몰라 - 브라우저에는 최초 호출한 URL 표시되고, 이동한 URL의 정보 확인 X - 현재 실행중인 페이지와 forward에 의해 호출될 페이지는 Request, Response 객체 공유함 - 이동할 URL로 요청정보를 그대로 전달 - 사용자가 최초로 요청한 요청정보는 다음 URL에서도 유효 - Redirect - 웹 브라우저에게 다른 페이지로 이동하라고 명령 - URL을 지시된 주소로 바꾸고 이동 - 새로운 Request, Response 객체 생성