OAuth2ProviderSupport.kt

package org.springframework.security.oauth2.server.authorization.authentication

import org.springframework.security.oauth2.core.ClaimAccessor
import org.springframework.security.oauth2.core.OAuth2AccessToken
import org.springframework.security.oauth2.core.OAuth2Token
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext
import java.time.Duration

/** 令牌请求错误 URI */
internal const val TOKEN_REQUEST_ERROR_URI =
    "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"

/** 构建锁定消息 */
internal fun buildLockMessage(remainingLock: Duration?): String {
    val seconds = maxOf(1L, remainingLock?.seconds ?: 0L)
    if (seconds >= 60) {
        val minutes = (seconds + 59) / 60
        return "账号已被锁定,请在${minutes}分钟后重试"
    }
    return "账号已被锁定,请在${seconds}秒后重试"
}

/** 构建访问令牌 */
internal fun buildAccessToken(
    authorizationBuilder: OAuth2Authorization.Builder,
    generatedAccessToken: OAuth2Token,
    tokenContext: OAuth2TokenContext,
): OAuth2AccessToken {
    var tokenType = OAuth2AccessToken.TokenType.BEARER
    if (generatedAccessToken is ClaimAccessor) {
        val cnfClaims = generatedAccessToken.getClaimAsMap("cnf")
        if (!cnfClaims.isNullOrEmpty() && cnfClaims.containsKey("jkt")) {
            tokenType = OAuth2AccessToken.TokenType.DPOP
        }
    }

    val accessToken =
        OAuth2AccessToken(
            tokenType,
            generatedAccessToken.tokenValue,
            generatedAccessToken.issuedAt,
            generatedAccessToken.expiresAt,
            tokenContext.authorizedScopes,
        )
    val accessTokenFormat = tokenContext.registeredClient.tokenSettings.accessTokenFormat

    authorizationBuilder.token(accessToken) { metadata ->
        if (generatedAccessToken is ClaimAccessor) {
            metadata[OAuth2Authorization.Token.CLAIMS_METADATA_NAME] = generatedAccessToken.claims
        }
        metadata[OAuth2Authorization.Token.INVALIDATED_METADATA_NAME] = false
        metadata[OAuth2TokenFormat::class.java.name] = accessTokenFormat.value
    }

    return accessToken
}