Move user infos to JWT tokens #19

Merged
william merged 12 commits from feature/12-user-info-in-jwt into develop 2021-12-02 21:58:27 -05:00
4 changed files with 46 additions and 22 deletions
Showing only changes of commit 25e61698ad - Show all commits

View File

@ -32,7 +32,7 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.11.3")
implementation("javax.xml.bind:jaxb-api:2.3.0")
implementation("io.jsonwebtoken:jjwt:0.9.1")
implementation("io.jsonwebtoken:jjwt-api:0.11.2")
implementation("org.apache.poi:poi-ooxml:4.1.0")
implementation("org.apache.pdfbox:pdfbox:2.0.4")
implementation("dev.fyloz.colorrecipesexplorer:database-manager:5.2")
@ -59,7 +59,7 @@ dependencies {
runtimeOnly("org.postgresql:postgresql:42.2.16")
runtimeOnly("com.microsoft.sqlserver:mssql-jdbc:9.2.1.jre11")
implementation("org.springframework.cloud:spring-cloud-starter:2.2.8.RELEASE")
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.2")
}
springBoot {

View File

@ -0,0 +1,3 @@
package dev.fyloz.colorrecipesexplorer
public typealias SpringUser = org.springframework.security.core.userdetails.User

View File

@ -1,23 +1,22 @@
package dev.fyloz.colorrecipesexplorer.config.security
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import dev.fyloz.colorrecipesexplorer.SpringUser
import dev.fyloz.colorrecipesexplorer.config.properties.CreSecurityProperties
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
import dev.fyloz.colorrecipesexplorer.model.account.UserLoginRequest
import dev.fyloz.colorrecipesexplorer.utils.buildJwt
import io.jsonwebtoken.ExpiredJwtException
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
import org.springframework.util.Assert
import org.springframework.web.util.WebUtils
import java.util.*
import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@ -28,7 +27,7 @@ val blacklistedJwtTokens = mutableListOf<String>()
class JwtAuthenticationFilter(
private val authManager: AuthenticationManager,
private val securityConfigurationProperties: CreSecurityProperties,
private val securityProperties: CreSecurityProperties,
private val updateUserLoginTime: (Long) -> Unit
) : UsernamePasswordAuthenticationFilter() {
private var debugMode = false
@ -49,29 +48,17 @@ class JwtAuthenticationFilter(
chain: FilterChain,
authResult: Authentication
) {
val jwtSecret = securityConfigurationProperties.jwtSecret
val jwtDuration = securityConfigurationProperties.jwtDuration
Assert.notNull(jwtSecret, "No JWT secret has been defined.")
Assert.notNull(jwtDuration, "No JWT duration has been defined.")
val userId = (authResult.principal as User).username
updateUserLoginTime(userId.toLong())
val expirationMs = System.currentTimeMillis() + jwtDuration
val expirationDate = Date(expirationMs)
val token = Jwts.builder()
.setSubject(userId)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, jwtSecret.toByteArray())
.compact()
response.addHeader("Access-Control-Expose-Headers", "X-Authentication-Expiration")
val user = (authResult.principal as SpringUser)
val token = user.buildJwt(securityProperties)
var bearerCookie =
"$authorizationCookieName=Bearer$token; Max-Age=${jwtDuration / 1000}; HttpOnly; SameSite=strict"
"$authorizationCookieName=Bearer$token; Max-Age=${securityProperties.jwtDuration / 1000}; HttpOnly; SameSite=strict"
if (!debugMode) bearerCookie += "; Secure;"
response.addHeader(
"Set-Cookie",
bearerCookie
)
response.addHeader(authorizationCookieName, "Bearer $token")
response.addHeader("X-Authentication-Expiration", "$expirationMs")
}
}
@ -115,6 +102,7 @@ class JwtAuthorizationFilter(
val jwtSecret = securityConfigurationProperties.jwtSecret
Assert.notNull(jwtSecret, "No JWT secret has been defined.")
return try {
val userId = Jwts.parser()
.setSigningKey(jwtSecret.toByteArray())
.parseClaimsJws(token.replace("Bearer", ""))

View File

@ -0,0 +1,33 @@
package dev.fyloz.colorrecipesexplorer.utils
import dev.fyloz.colorrecipesexplorer.SpringUser
import dev.fyloz.colorrecipesexplorer.config.properties.CreSecurityProperties
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.io.Encoders
import io.jsonwebtoken.security.Keys
import java.util.*
data class Jwt(
val subject: String,
val secret: String,
val duration: Long,
val signatureAlgorithm: SignatureAlgorithm = SignatureAlgorithm.HS512
)
fun SpringUser.buildJwt(properties: CreSecurityProperties) =
Jwt(this.username, properties.jwtSecret, properties.jwtDuration).build()
fun Jwt.build(): String {
val expirationMs = System.currentTimeMillis() + this.duration
val expirationDate = Date(expirationMs)
val base64Secret = Encoders.BASE64.encode(this.secret.toByteArray())
val key = Keys.hmacShaKeyFor(base64Secret.toByteArray())
return Jwts.builder()
.setSubject(this.subject)
.setExpiration(expirationDate)
.signWith(key)
.compact()
}