프로젝트에서 jwt를 이용한 회원 인증/인가를 만들기는 했지만 잘 파악하고 만든 것 같지 않다. 그래서 인증/인가에 대해 다시 정리하며 리팩토링하려 한다.
인증 :
네트워크나 서버에 접속할 때, 본인 여부와 정규 이용자 여부를 확인하는 방법. 일반적으로 사용자 아이디와 패스워드의 조합으로 본인을 특정한다.
인가 : 특정한 프로그램, 데이터 또는 시스템 서비스 따위에 접근할 수 있는 권한이 주어지는 것
즉 인증은 사용자를 특정하는 것이고, 인가는 접근권한을 허가하는 것이다.
oauth2는 인증/인가를 위한 라이브러리인데, 이것이 성립하기 위해서는 4가지의 요소가 필요하다.
우리가 게임에서 구글oauth로 인가를 받아 접속을 한다면
우리(Resource owner), 게임(Client), 구글의 서버(Authorization server, Resource Server)=OAuth Provider 이 된다.
권한 부여 승인코드(authorization code) 방식의 grant를 사용하므로 Client부분은 일반적으로 Client측의 서버 부분이 될 것이다.
권한 부여 승인 코드(authorization code)가 전달되는 uri는 spring security에서는 기본설정은
(구글 provider의 경우)http://localhost:8080/login/oauth2/code/google
이거나 본인이 설정한다면
spring.security.oauth2.client.registration.google.redirectUri=http://localhost:8080/oauth2/callback/{registrationId}
과 같이 spring설정파일에 작성할 수 있다.
프론트서버-백엔드서버- authorization server에서는
프론트 쪽에서 백엔드의 authorizationendpoint에 접근
-/oauth2/authorization/google 과 같은 uri에 접근
authorization server에 제어권이 넘어가며 해당 provider의 로그인 페이지가 노출
사용자가 로그인
정상적으로 로그인이 되었다면 authorization code를 백엔드의 redirect-uri로 전송.
ex)login/oauth2/code/google
백엔드에서 authorization code와 client-secret,유저 정보들을 함께 authorization server에 전송하며 access token을 요청
받은 정보들을 기반으로 access token생성 후 백엔드에 전달.
백엔드에서 access token을 포함시켜 최초로 인증을 요구했던 프론트 요청의 redirect uri로 이동.
프론트에서 받은 access token을 포함하며 추가적인 요청
-> 인가 후 요청에 따른 자원 전달.
- 의문점
spring boot의 예제를 보았는데 authorization code를 받은 후 accesstoken을 요청하는 controller가 따로 없었다.
AuthenticationSuccessHandler를 이용하면 authoroization server에 access token을 요청하지 않아도 백엔드에서 알아서 accesstoken을 생성해 프론트로 redirect시킬 수는 있다.
하지만 예제에서는 어떻게 인증서버에 access token을 요청했을까?
예제: https://spring.io/guides/tutorials/spring-boot-oauth2/
프론트에서 authorizationendpoint진입.
구글 로그인 화면.
로그인 -> 로그인 성공 ->
(userInfoEndPoint) customOauth2UserService 로 진입
customOauth2UserService에서 Oauth2UserRequest를 기반으로 유저정보를 받아옴(loaduser).
이 유저가 DB에 존재하지않으면 새로운 유저로 판단해 db에 저장.
이미 있던 유저인데 수정된 정보가 있으면 db에 갱신.
successhandler실행 -> accesstoken만들어서 프론토로 redirect.
jwt를 통한 인증은 아래와 같은 흐름이다.
//여기서 토큰의 생성
spring에서는 이를위해 일반적으로 다음과 같은 요소들를 구현해야 한다.
1. 클라이언트의 요청이 dispatcher servlet에 도달하기 전 요청을 확인
2. 요청에 따라 토큰 생성 및 반환
3. 요청에 토큰이 있다면 유효성 검증
4. 토큰이 유효할 경우 권한에 따른 접근 허가
이 요소들을 위의 spring security 요소들로 구현한다면
이렇게 구현이 가능하다.
사실 위에서 authenticationFilter로 뭉뚱그려 하나로 그려져 있지만 spring security는 servlet이 요청을 받기 전 많은 filterchain을 거친다.
이 필터들 중 어디에 내가 작성한 인증로직을 가진 커스텀필터를 위치시킬지 security에 설정을 해야 한다. 아래와 같이 addFilterBefore()을 이용한다.
@Override
protected void configure(HttpSecurity http) throws Exception {
// ...
http
.addFilterBefore(
customAuthenticationTokenFilter(authenticationManagerBean()),
UsernamePasswordAuthenticationFilter.class);
}
참고:
https://wonyong-jang.github.io/spring/2020/08/20/Spring-Security-oauth2-jwt-1.html
https://velog.io/@sa833591/Spring-Security-5
이전: tokenAuthenticationFilter/ tokenProvider/customUserDetailService
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-jwt
https://velog.io/@agugu95/OAuth%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84%EC%9D%84-%EC%9C%84%ED%95%9C-Spring-Security-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0#spring-security%EC%99%80-rest-api
https://mygumi.tistory.com/10?category=642348
https://blinders.tistory.com/63 [글쓰는 개발자:티스토리]