Skip to content

Commit

Permalink
feat: implement get current user info
Browse files Browse the repository at this point in the history
  • Loading branch information
mutoe committed Sep 13, 2021
1 parent f990413 commit 930e651
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 34 deletions.
23 changes: 23 additions & 0 deletions http/auth.http
Expand Up @@ -20,6 +20,8 @@ client.test("Register", function() {
client.assert(user.username === "foobar", "username not match")
client.assert(user.email === "foo@bar.com", "email not match")
client.assert(user.token, "token not exist")

client.global.set("token", user.token)
})
%}

Expand Down Expand Up @@ -65,6 +67,8 @@ client.test("Login", function() {
client.assert(user.username === "foobar", "username not match")
client.assert(user.email === "foo@bar.com", "email not match")
client.assert(user.token, "token not exist")

client.global.set("token", user.token)
})
%}

Expand All @@ -87,3 +91,22 @@ client.test("Login with incorrect email", function() {
client.assert(response.body.message === "Email is not exist", "error message not match")
})
%}

###

# Get current user info
GET {{host}}/user
Authorization: Bearer {{token}}

> {%
client.test("Get current user info", function() {
client.assert(!!client.global.get("token"), "should register or login first")
client.assert(response.status === 200, "response status is not 200")

client.assert(response.body.user, "user not exist")
var user = response.body.user
client.assert(user.username === "foobar", "username not match")
client.assert(user.email === "foo@bar.com", "email not match")
client.assert(user.token, "token not exist")
})
%}
Expand Up @@ -13,7 +13,7 @@ import javax.servlet.http.HttpServletResponse
class JwtAuthenticationFilter(
private val jwtTokenUtil: JwtTokenUtil,
) : OncePerRequestFilter() {
private val tokenHeader = "Authentication"
private val tokenHeader = "authorization"
private val tokenPrefix = "Bearer "

override fun doFilterInternal(
Expand Down
Expand Up @@ -5,36 +5,44 @@ import com.mutoe.realworld.adapter.inbound.user.dto.RegisterDto
import com.mutoe.realworld.adapter.inbound.user.dto.UserDto
import com.mutoe.realworld.adapter.inbound.user.dto.UserDto.Companion.toDto
import com.mutoe.realworld.adapter.security.utils.JwtTokenUtil
import com.mutoe.realworld.application.AuthApplication
import com.mutoe.realworld.application.UserApplication
import io.jsonwebtoken.Claims
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("users")
class UserController(
private val authApplication: AuthApplication,
private val application: UserApplication,
private val jwtTokenUtil: JwtTokenUtil,
) {

@PostMapping
@PostMapping("users")
fun register(@RequestBody request: RegisterDto): UserDto {
val user = authApplication.register(request.toCommand())
val user = application.register(request.toCommand())
val token = jwtTokenUtil.generateToken(user.id, user.email)
return user.toDto(token)
}

@PostMapping("login")
@PostMapping("users/login")
fun login(@RequestBody request: LoginDto): UserDto {
val user = authApplication.login(request.toCommand())
val user = application.login(request.toCommand())
val token = jwtTokenUtil.generateToken(user.id, user.email)
return user.toDto(token)
}

@PostMapping("logout")
@PostMapping("users/logout")
fun logout() {
SecurityContextHolder.clearContext()
}

@GetMapping("user")
fun getCurrent(@AuthenticationPrincipal principal: Claims): UserDto {
val user = application.getCurrent(principal.id.toInt())
val token = jwtTokenUtil.generateToken(user.id, user.email)
return user.toDto(token)
}
}
Expand Up @@ -9,6 +9,9 @@ import org.springframework.stereotype.Component
class UserRepositoryImpl(
private val dao: UserDao,
) : UserRepository {
override fun get(id: Int): User {
return dao.getById(id).toDomain()
}

override fun find(email: String): User? {
return dao.findByEmail(email)?.toDomain()
Expand Down
@@ -1,7 +1,6 @@
package com.mutoe.realworld.adapter.security.utils

import io.jsonwebtoken.Claims
import io.jsonwebtoken.JwtException
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.security.Keys
Expand All @@ -13,7 +12,6 @@ import java.util.Date

@Component
class JwtTokenUtil(
@Value("\${conduit.jwt.secret}") private val secret: String,
@Value("\${conduit.jwt.expiration}") private val expiration: String,
) {
private val key = Keys.secretKeyFor(SignatureAlgorithm.HS256)
Expand All @@ -24,52 +22,47 @@ class JwtTokenUtil(

fun validateToken(token: String): Boolean = !isInvalid(token)

fun getUserIdFromToken(token: String): Int {
return parseJws(token)!!.id.toInt()
}

fun getAuthentication(token: String): Authentication {
val claims = parseJws(token)!!
return UsernamePasswordAuthenticationToken(claims.id, token)
val claims = parseJws(token)
return UsernamePasswordAuthenticationToken(claims, token, listOf())
}

private fun generateJws(userId: Int, email: String): String {
return Jwts.builder()
.setIssuer("conduit")
.setAudience(email)
.setId(userId.toString())
.setSubject(email)
.setNotBefore(Date())
.setExpiration(Date(System.currentTimeMillis() + expiration.toLong() * 60 * 1000))
.setIssuedAt(Date())
.signWith(key)
.compact()
}

private fun parseJws(token: String): Claims? {
return try {
Jwts.parserBuilder()
.setSigningKey(secret)
.build()
.parseClaimsJws(token)
.body
} catch (e: JwtException) {
null
}
private fun parseJws(token: String): Claims {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.body
}

private fun isInvalid(token: String): Boolean {
return try {
val claims = parseJws(token)
claims!!.issuedAt.before(Date()) && isExpired(token)
claims.notBefore.before(Date()) && isExpired(token)
} catch (e: Exception) {
false
true
}
}

private fun isExpired(token: String): Boolean {
return try {
val claims = parseJws(token)
claims!!.expiration.before(Date())
claims.expiration.before(Date())
} catch (e: Exception) {
false
true
}
}
}
Expand Up @@ -3,16 +3,20 @@ package com.mutoe.realworld.application
import com.mutoe.realworld.adapter.inbound.user.command.LoginCommand
import com.mutoe.realworld.adapter.inbound.user.command.RegisterCommand
import com.mutoe.realworld.domain.user.User
import com.mutoe.realworld.domain.user.UserRepository
import com.mutoe.realworld.domain.user.UserService
import org.springframework.stereotype.Service

@Service
class AuthApplication(
class UserApplication(
private val userService: UserService,
private val userRepository: UserRepository,
) {
fun register(command: RegisterCommand): User =
userService.register(command.email, command.username, command.password)

fun login(command: LoginCommand): User =
userService.login(command.email, command.password)

fun getCurrent(id: Int): User = userRepository.get(id)
}
@@ -1,6 +1,7 @@
package com.mutoe.realworld.domain.user

interface UserRepository {
fun get(id: Int): User
fun find(email: String): User?
fun findByUsername(username: String): User?
fun save(user: User): User
Expand Down
1 change: 0 additions & 1 deletion src/main/resources/application.properties
@@ -1,4 +1,3 @@
conduit.jwt.secret=mutoe
conduit.jwt.expiration=60
spring.datasource.url=jdbc:postgresql://localhost:5442/postgres
spring.datasource.username=postgres
Expand Down

0 comments on commit 930e651

Please sign in to comment.