분류 전체보기 1341

시큐리티 인증 및 인가 흐름 요약

ServletFilter 사용자 요청 시 DelegatingFilterProxy 클래스가 요청을 받는다. DelegatingFilterProxy는 서블릿 필터로, 스프링의 기능을 사용하지 못하기 때문에 FilterChainProxy로 요청을 전달해 주는 역할만 한다. FilterChainProxy는 여러 개의 필터를 가지고 있고, 하나씩 호출하며 인증을 진행한다(Authentication) Authentication 인증 필터에는 여러 종류가 있지만, 그 중 가장 많이 사용하는 UserPasswordAuthenticationFilter이다. UserPasswordAuthenticationFilter가 인증 요청을 받고(/login), Authentication 객체를 만들게 된다. Password, Id..

AuthenticationEntryPoint 이해

SpringSecurity는 기본적으로 2개의 설정(FormLoginConfigurer, HttpBasicConfigurer) 방식으로 설정한다. FormLoginConfigurer, HttpBasicConfigurer 든 예외처리를 하기 위해서는 EntryPoint에 대한 설정을 해야 한다 ExceptionHandlingConfigurer에서 EntryPoint에 대한 설정을 한다 인증 예외가 발생했을 때, ExceptionHandlingConfigurer에서 후속처리를 어떻게 진행할 것인지 결정한다. FormLoginConfigurer 동작 과정 FormLoginConfigurer에서 인증 에러가 발생했을 때의 EntryPoint를 결정해야 한다. FormLoginConfigurer에서 인증 에러가 ..

서비스 연동 & 프론트 연동

서비스 연동 Issue-service/WebConfig @Component class AuthUserHandlerArgumentResolver( @Value("\${auth.url}") val authUrl: String, ) : HandlerMethodArgumentResolver { override fun supportsParameter(parameter: MethodParameter): Boolean = AuthUser::class.java.isAssignableFrom(parameter.parameterType) //해당 조건이 맞아야 조건 통과 override fun resolveArgument( parameter: MethodParameter, mavContainer: ModelAndViewC..

리포트 조회 / 내정보 수정

리포트 조회 Controller @GetMapping("/{userId}/username") suspend fun getUsername(@PathVariable userId: Long): Map { return mapOf("reporter" to userService.get(userId).username) } 이전에 만들었던 get메서드를 재활용했다. username만 반환하면 되므로 간단하게 map을 사용했다. 내 정보 수정 Controller @PostMapping("/{id}", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) suspend fun edit( @PathVariable id: Long, @ModelAttribute request: UserEdi..

내정보 조회

Controller @GetMapping("/me") //pathVariable 로 Id를 받게 되면, 헤커가 다른 유저 정보도 알수 있게된다(보안에 취약) suspend fun get( @AuthToken token: String, ): MeResponse { return MeResponse(userService.getByToken(token)) } MeResponse data class MeResponse( val id: Long, val profileUrl: String?, val username: String, val email: String, val createdAt: LocalDateTime?, val updatedAt: LocalDateTime?, ) { companion object { o..

로그인과 로그아웃

로그인 Controller @PostMapping("/signin") suspend fun signIn(@RequestBody signInRequest: SignInRequest): SignInResponse { return userService.signIn(signInRequest) } SignInRequest data class SignInRequest( val email:String, val password: String, ) SignInResponse data class SignInResponse( val email: String, val username: String, val token: String, ) Service @Service class UserService( private val us..

회원가입

domain User @Table("users") data class User( @Id val id: Long? = null, @Column val email: String, @Column val password: String, @Column val username: String, @Column val profileUrl: String? = null, @Column("created_at") @CreatedDate val createdAt: LocalDateTime? = null, @Column("updated_at") @LastModifiedDate val updatedAt: LocalDateTime? = null, ) User 도메인을 작성한다. UserRepository interface UserRe..

JWT 기반 인증 구현

build.gradle dependencies { // JWT 인증 implementation("com.auth0:java-jwt:3.19.2") } 해당 의존성을 추가하여 JWT 기능을 사용하자 application.yml jwt: issuer: java #프로젝트 이름 subject: auth expires-time: 3600 #1시간 secret: my-secret JWT에 관련된 설정 추가 issuer : 토큰을 발급한 발급자 subject: claim의 주제(토큰이 갖는 문맥) expires-time: 만료 시간 secret: 비밀 키 JWTUtils object JWTUtils { fun createToken(claim: JWTClaim, properties: JWTProperties) = J..

토큰 기반 인증

세션 기반 인증 세션 기반 인증 방식은 서버가 클라이언트의 세션 정보를 저장하고 있는 stateful 한 방식이다. 사용자가 로그인을 하게 되면, 서버는 사용자 정보 검증 후, 세션 id를 발급하고 브라우저의 쿠키에 저장한다. 브라우저는 모든 요청마다 쿠키에 있는 세션 id를 포함, 서버는 세션 id를 통해 유저 정보를 세션 스토리지에서 조회 일반적으로 서버 메모리, DB 등을 사용해 세션을 저장한다. 세션은 서버에서 만료시켜, 클라이언트의 권한을 회수할 수 있다. 단점 서버 확장 어렵다(분산 환경에서는 세션을 공유할 수 있는 세션 클러스터링 필요) 중앙에서 세션을 관리할 수 있는 세션 DB를 구축해야 한다. 요청이 많아지면 세션 조회에 따른 DB 부하가 심해질 수 있다. 토큰 기반 인증 토큰 기반 인증..

공통 에러 처리

에러 응답 모델 정의 data class ErrorResponse( val code: Int, val message: String, ) code로 어떤 에러가 발생했는지 정의한다. Http status code만으로 모든 에러에 대한 케이스를 처리하기 힘들기 때문엔 code를 정의하였다. 에러가 발생했을 때 나타낼 메시지를 표시한다. 메시지에 stacktrace와 같이 언어, 프레임워크 정보, DB필드 등이 노출되면 절대 안 된다. Exception 구조 정의 sealed class ServerException( val code: Int, override val message: String, ): RuntimeException(message) 최상위 ServerException을 sealed 클래스로 정..