웹 개발을 하는 사람들이 가장 많이 사용하는 기능중 하나는 로그인 기능일 것이다. 새로운 프로젝트를 생성 할 때 마다 로그이 기능을 만들고 보안을 신경쓰는 작업은 매우 불편한 작업이다. 이런 반보되는 불편함을 싫어하는 개발자들이 이것을 가만히 뒀을리가 없다. 스프링은 반복적이고 귀찮은 일을 대신 처리해주는 대표적이 프레임워크익고 당연하게도 로그인 기능을 구현해주는 라이브러리가 있다. 그 라이브러리를 spring websecurity라고 하다.
이미 작성되어있는 webSecurityConfigureAdpter를 상속 받아서 나에게 맞춰서 커스텀하겠다라고 선언을 하고
configure를 오버라이딩해서 원하는 부분을 수정을 하면된다.
내가 입력한 정보로 로그인을 할 수 있는지를 체크해주는 부분은 websecurity안에 들어있는 UserDetailsService 안에 담겨있다. 지금 나는 이 부분을 내 프로젝트에 맞게 설정을 바꿔주고 싶어서 Custom class에 상속하고 Custom 클래스를 만들어줬다.
UserDetailsService안에 UserDetails라는 클래스를 오버라이딩해서 원하는 작업을 수행하도록 바꿔줬다.
문제가 없다면 db에 저장되어 있는 user 정보를 createUser에 전달해줬다.
User 객체
createUser 메소드는 전달 받은 user정보(username 과 user)를 통해서 활성화 검사를 진행하고 해당 유저에 들어있는 권한들을 뽑아서 유저가 가지고 있는 권한과 이름 그리고 비밀번호를 UserDetailsService에 들어있는 UserDetails의 User로 전달해 준다.
UserDetails의 User메소드는 다음과 같이 생겼다
이렇게 생긴 곳에 정보를 넣어서 User객체를 생성한다.
나중에 홈페이지에서 지금 사용자 로그인을 한 사람인지 아니면 로그인을 하지 않은 사람인지를 확인 할 때 아래 처럼 사용을 하는데 userDetails에는 아까 만들어준 User객체가 들어있어서
사용자의 이름과 닉네임 그리고 권한들을 확인 할 수 있다.
AuthController에서 기존에 security가 생성 될 때 같이 생성된 AuthenticationManagerBuilder(인증 확인)를 사용한다고 설정해준다.
로그인을 요청한 정보가 들어오면("/api/authenticate/{정보}")
UsernamePasswordAuthenticationToken을 사용해서 {정보}에 담겨있는 username,password를 넣어서 새로운 객체(authenticationToken)을 생성해준다.
생성한 객체를 AuthenticationManagerBuilder(인증 확인)안에 들어있는 메소드에 넣어준 뒤에 security를 생성 할 때 같이 만들어진 Authentication 안에 담아줍니다. 그리고 authentication을 다시 SecurityContextHolder에 담아준다.
최종적으로 Jwt 토크을 생성하고 생성한 Jwt토큰을 HTTPHeader안에 넣어서 반환해준다.
TokenProvider에서
토큰을 생성하는데 토큰이 만들어지는 날짜와 토큰의 만료기간을 담아서 토큰을 생성한다.
security 구조를 보면 authenticationFilter가 있는데 이를 들어가보며
이런 부분이 나오는데 authenticationFilter에 대한 규칙 및 검증 방식을 정의하는 곳이다.
여기서 우리가 만들어준 Filter을 등록이 가능하다.
여기서 customFilter라는 filter를 등록해주고 UsesrnamePasswordAuthenticationFilter를 검사할 것이라고 설정해줬다. customfilter는 JwtFilter 타입이다.
JwtFilter를 살펴보자
Jwt 필터는 다음과 같이 생겼다.
jwt 필터에서는 doFilter를 통해서 전달 받은 토큰을 검증한다.
doFilter가 실행이되면 resolveToken이라는 메소드를 통해서 request Header안에 들어있는 토큰을 꺼내준다.
그러면 꺼내준 토큰 정보를 주입받은 TokenProvider의 validateToken이라는 메소드를 사용해서 유효성을 검사한다.
validateToken은 TokenProvider 안에 있고 다음과 같이 생겼다.
문제가 없다면 TokenProvider의 getAuthentication 메소드를 실행하고 getAuthentication 메소드는 다음과 같이 생겼다.
이 부분에서 전달받은 토큰을 복호화 시키고 토큰에 들어있던 암호들과 권한들을 User 객체 안에 저장해준다.
여기서 User은 UserDetails안에 들어있는 User 객체를 의미한다.
이렇게 저장한 객체를 Security context = logger 에 저장해준다.
동작 원리 4에서 저장한 logger를 호출하여서 현재 로그인 되어있는 사용자의 정보를 확인하고 동작을 수행 할 수 있다.