@Configuration
class PasswordEncoderConfig {
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
}
이게 있어야 비밀번호를 안전하게 처리할수 있다.
하지만 이것만으론 부족하고, 회원가입을 할때에 페스워드인토더랑 연결이 되야한다.
data class AdminSignUpRequest(
val email: String,
val password: String,
val passwordCheck: String,
var nickname: String,
var address: String,
var phoneNumber: String
) {
fun toEntity(passwordEncoder: PasswordEncoder): Admin {
return Admin(
email = email,
password = passwordEncoder.encode(password), // 비밀번호 암호화
nickname = nickname,
address = address,
phoneNumber = phoneNumber
)
}
}
그러면 이제 제대로 암호화가 된다.
그러면 이제 jwt를 만들어야 한다.
@Component
class JwtPlugin(
@Value("\${auth.jwt.issuer}") private val issuer: String,
@Value("\${auth.jwt.secret}") private val secret: String,
@Value("\${auth.jwt.accessTokenExpirationHour}") private val accessTokenExpirationHour: Long,
) {
fun validateToken(jwt: String): Result<Jws<Claims>> {
return kotlin.runCatching {
val key = Keys.hmacShaKeyFor(secret.toByteArray(StandardCharsets.UTF_8))
Jwts.parser().verifyWith(key).build().parseSignedClaims(jwt)
}
}
fun generateAccessTokenForSocialUser(
subject: String,
nickname: String,
email: String,
roles: List<String>, // 역할 정보 추가
httpServletResponse: HttpServletResponse,
): String {
val token = generateToken(subject, nickname, email, roles, Duration.ofHours(accessTokenExpirationHour))
addTokenToCookie(token, httpServletResponse)
return token
}
fun generateAccessToken(
subject: String,
nickname: String,
email: String,
roles: List<String>, // 역할 정보 추가
): String {
return generateToken(subject, nickname, email, roles, Duration.ofHours(accessTokenExpirationHour))
}
private fun generateToken(
subject: String,
nickname: String,
email: String,
roles: List<String>, // 역할 정보 추가
expirationPeriod: Duration,
): String {
val claims: Claims = Jwts.claims()
.add(mapOf(
"email" to email,
"nickname" to nickname,
"roles" to roles // 역할 정보를 클렘에 포함
))
.build()
val key = Keys.hmacShaKeyFor(secret.toByteArray(StandardCharsets.UTF_8))
val now = Instant.now()
return Jwts.builder()
.subject(subject)
.issuer(issuer)
.issuedAt(Date.from(now))
.expiration(Date.from(now.plus(expirationPeriod)))
.claims(claims)
.signWith(key)
.compact()
}
private fun addTokenToCookie(
token: String,
httpServletResponse: HttpServletResponse,
) {
val cookie = Cookie("jwt_token", token)
cookie.isHttpOnly = false
cookie.maxAge = (accessTokenExpirationHour * 60 * 60 * 24 * 7).toInt() // 약 8.4일
cookie.path = "/"
httpServletResponse.addCookie(cookie)
}
}
기계녀석의 설명.
validateToken(jwt: String): 제공된 JWT의 유효성을 검사합니다. 유효한 토큰인 경우 Jws<Claims>를 반환하고, 그렇지 않을 경우 예외를 발생시킵니다.
generateAccessTokenForSocialUser(...): 소셜 사용자에게 액세스 토큰을 생성하고, 이 토큰을 HTTP 응답의 쿠키에 추가합니다. 사용자의 식별자(subject), 별명(nickname), 이메일(email), 역할(roles)을 기반으로 토큰을 생성합니다.
generateAccessToken(...): 주어진 사용자 정보를 바탕으로 액세스 토큰을 생성합니다. 이 메소드는 generateAccessTokenForSocialUser와 유사하지만, 쿠키에 토큰을 추가하는 작업은 수행하지 않습니다.
generateToken(...): 실제로 JWT를 생성하는 핵심 메소드입니다. 사용자 정보와 만료 기간을 받아 JWT를 생성하고 반환합니다. Jwts.builder()를 사용하여 토큰을 생성합니다.
addTokenToCookie(token: String, httpServletResponse: HttpServletResponse): 생성된 토큰을 HTTP 응답의 쿠키에 추가하는 메소드입니다. 쿠키의 이름은 jwt_token이며, HttpOnly 속성을 false로 설정하여 JavaScript를 통해 쿠키에 접근할 수 있도록 합니다. 쿠키의 유효 기간은 액세스 토큰의 만료 시간과 동일하게 설정됩니다.
그런데, 어드민을 일반 유저와 구분하기 위해 role을 찿아보는 중이다.
그리고 실행파일을
@EnableJpaAuditing
@EnableCaching
@SpringBootApplication
@EnableAsync
class BoardApplication
fun main(args: Array<String>) {
runApplication<BoardApplication>(*args)
}
이렇게 만들어 보았다.
spring:
datasource:
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: sa
password:
driver-class-name: org.h2.Driver
h2:
console:
enabled: true
path: /h2-console
어플리케이션 .yml도 이렇게 만들면 h2를 사용할수있다.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'adminController' defined in file [C:\Users\asdf\IdeaProjects\Board\build\classes\kotlin\main\org\example\domain\admin\controller\AdminController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'adminServiceImpl' defined in file [C:\Users\asdf\IdeaProjects\Board\build\classes\kotlin\main\org\example\domain\admin\service\AdminServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 2: Error creating bean with name 'jwtPlugin' defined in file [C:\Users\asdf\IdeaProjects\Board\build\classes\kotlin\main\org\example\domain\infra\jwt\JwtPlugin.class]: Unexpected exception during bean creation
왠지모르겠는 오류 발생해서 jwt를 더 추가해보기로 함