添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
唠叨的石榴  ·  已解决: Re: PN7462 RTOS ...·  2 月前    · 
乐观的四季豆  ·  【漫画说纪】 ...·  4 月前    · 
坚韧的哑铃  ·  新闻 < KoBiz - Korean ...·  5 月前    · 

[Spring Boot] Filter와 Interceptor를 이용한 로그인 확인

Spring Boot

2022-10-09 15:33 (KST)

Language :

전제: 로그인 시 발급되는 세션 키를 header에 가지고 있는 사용자만 사이트 이용 가능

Annotation

로그인이 필요한 서비스는 Controller Method에 Annotation을 붙인다.

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class LoginCheck()

Exception

세션 키가 없으면 401 에러를 발생시킨다.

import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.ResponseStatus
@ResponseStatus(HttpStatus.UNAUTHORIZED, reason = "Unauthorized")
class UnauthorizedException : RuntimeException()

Filter

Header에 유효한 세션 키가 있는 지 확인하여 Request에 저장한다.

import com.dev.service.SessionService
import org.springframework.http.HttpHeaders
import org.springframework.stereotype.Component
import org.springframework.util.Base64Utils
import org.springframework.web.filter.OncePerRequestFilter
import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@Component
class SessionInjectionFilter(
    private val sessionService: SessionService,
) : OncePerRequestFilter() {
    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain,
        sessionInjection(request)
        filterChain.doFilter(request, response)
    private fun sessionInjection(request: HttpServletRequest) {
        val header = request.getHeader(HttpHeaders.AUTHORIZATION) ?: return
        val authType = "Bearer "
        if (!header.startsWith(authType)) return
        val encryptedSessionKey = header.removePrefix(authType)
        val sessionKey = String(Base64Utils.decodeFromString(encryptedSessionKey))
        val session = sessionService.getSession(sessionKey) ?: return
        request.setAttribute("session", session)
}

Interceptor

Controller로 요청이 넘겨지기 전에 Method에 Annotation LoginCheck가 붙어 있으면 로그인을 확인한다.

import com.dev.annotation.LoginCheck
import com.dev.exception.UnauthorizedException
import org.springframework.stereotype.Component
import org.springframework.web.method.HandlerMethod
import org.springframework.web.servlet.HandlerInterceptor
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@Component
class LoginCheckInterceptor : HandlerInterceptor {
    override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
        if (handler !is HandlerMethod) return true
        handler.getMethodAnnotation(LoginCheck::class.java) ?: return true
        if (request.getAttribute("session") == null) throw UnauthorizedException()
        return true
}

WebMvcConfigurer

Custom Interceptor를 등록한다.

@Configuration
class WebMvcConfig : WebMvcConfigurer {
    override fun addInterceptors(registry: InterceptorRegistry) {
        registry.addInterceptor(LoginCheckInterceptor())
            .addPathPatterns("/api/v1/session")
}

Spring 2.x 에서 정적 리소스를 요청할 때에도 Interceptor 가 호출되기 때문에 HandlerMethod가 전달되는 Url을 지정해 주어야 오류가 발생하지 않는다.

java.lang.ClassCastException: class org.springframework.web.servlet.resource.ResourceHttpRequestHandler cannot be cast to class 

Controller

@LoginCheck
@GetMapping("/session")
fun getSession(request: HttpServletRequest): ResponseEntity<Any> {
    val session = request.getAttribute("session") as Session