2018년 6월 19일 화요일

Spring security API Key authenticate

Filter단에서 Id, ApiKey로 API 사용에 대한 인증하고 싶은 경우 다음과 같이 간단하게 하면 됨.

막상 짜고 나니 Interceptor에서 처리해야 해서 기록용으로 남긴다.


class CpApiAuthFilter : AbstractPreAuthenticatedProcessingFilter() {

    val log = LoggerFactory.getLogger(javaClass)!!

    override fun getPreAuthenticatedCredentials(request: HttpServletRequest): CpCredential {
        val apiKey:String? = request.getHeader("x-sample-api-key")
        val cpId:String? = request.getHeader("x-sample-cp-id")
        log.debug("api key auth: cpId=$cpId,apiKey=$apiKey")

        return CpCredential(apiKey, cpId)
    }

    override fun getPreAuthenticatedPrincipal(request: HttpServletRequest): Any {
        return ""
    }
}

data class CpCredential(
        val apiKey:String? = null,
        val cpId:String? = null
){
    fun isValid(): Boolean {
        if(apiKey.isNullOrBlank() || cpId == null || apiKey?.length!! < 5 )
            return false

        try {
            cpId.toLong()
        } catch (e:Exception){
            return false
        }
        return true
    }
    fun getCpId():Long = cpId!!.toLong()
}

class CpApiAuthManager
@Autowired constructor(private val repository: CpRepository)
    : AuthenticationManager {
    override fun authenticate(authentication: Authentication): Authentication {
        val credential = authentication.principal as CpCredential

        if(credential.isValid().not())
            throw BadCredentialsException("apiKey, cpId not found or not expected value.")
        val cpId = credential.getCpId()
        val cp = repository.findOne(cpId)

        if (cp == null || !cp.status)
            throw BadCredentialsException("cp not found or cp expired.")

        if(cp.apiKey != credential.apiKey)
            throw BadCredentialsException("cpId and apiKey do not matched.")

        authentication.isAuthenticated = true
        return authentication
    }
}

인증용 Filter, Manager는 위처럼 생성.

security에 적용하는 건 아래 처럼 하면 됨.


    @Bean
    @Order(1)
    fun webSecurityConfigurerAdapter(): WebSecurityConfigurerAdapter {
        return object : WebSecurityConfigurerAdapter() {
            override fun configure(http: HttpSecurity) {

                http.addFilter(CpApiAuthFilter(CpApiAuthManager(cpRepository)))

                http.headers().frameOptions().disable().xssProtection().xssProtectionEnabled(true)
                        .and().contentTypeOptions()
                        .and().cacheControl().disable()
                        .and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
            }
        }
    }


일부 코드만 발췌한거라 동작을 안할 수도 있다.ㅎㅎㅎ