Spring

Spring Boot에서 Firebase ID 토큰으로 사용자 인증

기록만이살길 2021. 3. 18. 07:04
반응형

Spring Boot에서 Firebase ID 토큰으로 사용자 인증

1. 질문(문제점):

현재 Authorization 헤더를 통해 보내는 Firebase ID 토큰을 사용하여 사용자를 인증하려고합니다. 그러나 모든 방법으로 각 요청에 대해 항상 HTTP 403 오류가 발생합니다. 내가 사용하는 토큰은 verifyIdToken(idToken)이것을 디버깅 할 때 메서드 가 예외를 던지지 않기 때문에 유효 하므로이 문제는 Firebase보다 Spring Security와 더 관련이 있다고 생각합니다.

그 이유는 무엇일까요?

내가 만든 Firebase 필터에 대한 내 코드 :

@Component
class FirebaseFilter : OncePerRequestFilter() {
    override fun doFilterInternal(request: HttpServletRequest,
                                  response: HttpServletResponse,
                                  filterChain: FilterChain) {
        val authToken = request.getHeader(AUTH_HEADER).substring(7)
        if (authToken!="") {
            SecurityContextHolder.getContext().authentication = getAuthentication(authToken)
            logger.debug("Successfully Authenticated")
        }
        filterChain.doFilter(request, response)
    }

    private fun verifyIdToken(idToken: String): FirebaseToken {
        require(idToken!="") { "idToken is blank" }
        return FirebaseAuth.getInstance().verifyIdToken(idToken)
    }

    private fun getAuthentication(idToken: String): UsernamePasswordAuthenticationToken {

        val token = verifyIdToken(idToken)
        return UsernamePasswordAuthenticationToken(token.uid,token)
    }

    companion object {
        private const val AUTH_HEADER = "Authorization"
    }
}

WebSecurityConfigurerAdapter의 코드 :

@EnableWebSecurity
@Configuration
class HttpConfig : WebSecurityConfigurerAdapter() {


    @Autowired
    lateinit var firebaseFilter: FirebaseFilter

    override fun configure(http: HttpSecurity) {
        http.cors().and().csrf().disable()
                .authorizeRequests()
                .anyRequest().authenticated().and()
                .addFilterBefore(firebaseFilter, UsernamePasswordAuthenticationFilter::class.java)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    }
}

2. 해결방안:

Ok 나는 해결책을 찾았고 내가 뭘 잘못했는지 생각했습니다. 인증 UsernamePasswordAuthenticationToken으로 내 경우에는 올바르지 않은을 반환했습니다 . 대신 AbstractAuthenticationToken다음과 같이 서브 클래 싱 하여 필터에 반환했습니다.

class FireBaseAuthenticationToken(val idToken: String): AbstractAuthenticationToken(null) {

    override fun getCredentials(): Any {
        TODO("Not yet implemented")
    }

    override fun getPrincipal(): Any {
        TODO("Not yet implemented")
    }
}

또한 Spring이이 토큰을 인증하는 방법이 필요하기 때문에 AuthenticationToken을 추가하는 것만으로는 충분하지 않습니다. 일반적으로 Spring은이 경우에 사용 가능한 AuthenticationProviders List을 반복합니다. 그러나 기본적으로 적절한 공급자를 사용할 수 없기 때문에 다음과 같이 자체적으로 구현해야했습니다.

@Component
class FireBaseTokenAuthenticationProvider : AuthenticationProvider {
    override fun authenticate(authentication: Authentication?): Authentication {
        val fireBaseAuthToken = authentication as FireBaseAuthenticationToken
        val fireBaseToken = FirebaseAuth.getInstance().verifyIdToken(fireBaseAuthToken.idToken)
        val userRecord = FirebaseAuth.getInstance().getUser(fireBaseToken.uid)
        val user = FirebaseUser(userRecord)
        println("user authenticated")
        return user
    }

    override fun supports(authentication: Class<*>?): Boolean {
        return authentication!!.isAssignableFrom(FireBaseAuthenticationToken::class.java)
    }
}

이제 모든 것이 잘 작동합니다! :)

65678522
반응형