Skip to content

Commit

Permalink
feat: OAuth支持客户端模式 #1252 (#1274)
Browse files Browse the repository at this point in the history
* feat: OAuth支持客户端模式 #1252

* feat: OAuth支持客户端模式 #1252

* feat: OAuth支持客户端模式 #1252
  • Loading branch information
yaoxuwan authored Oct 17, 2023
1 parent 3f86649 commit c0632e1
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ enum class AuthorizationGrantType {
AUTHORIZATION_CODE,
// 简化模式,尚未支持
// IMPLICIT,
// 客户端模式,尚未支持
// CLIENT_CREDENTIALS,
// 客户端模式
CLIENT_CREDENTIALS,
// 密码模式,尚未支持
// PASSWORD,
// 平台账号验证
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ data class TOauthToken(
val expireSeconds: Long?,
val type: String,
val accountId: String,
val userId: String,
var userId: String,
var scope: Set<ResourceType>?,
var issuedAt: Instant,
var idToken: IdToken?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,7 @@ class AccountServiceImpl constructor(
private fun findAccountAndCheckOwner(appId: String, userId: String): TAccount {
val account = accountRepository.findOneByAppId(appId)
?: throw ErrorCodeException(AuthMessageCode.AUTH_APPID_NOT_EXIST)
val admin = userService.getUserInfoById(userId)?.admin ?: false
if (!account.owner.isNullOrBlank() && userId != account.owner && !admin) {
if (!account.owner.isNullOrBlank() && userId != account.owner) {
throw ErrorCodeException(AuthMessageCode.AUTH_OWNER_CHECK_FAILED)
}
return account
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ class OauthAuthorizationServiceImpl(
}

override fun createToken(generateTokenRequest: GenerateTokenRequest) {
Preconditions.checkNotNull(generateTokenRequest.code, GenerateTokenRequest::code.name)
val authorization = HeaderUtils.getHeader(HttpHeaders.AUTHORIZATION)?.removePrefix(BASIC_AUTH_PREFIX)
val clientId: String
val clientSecret: String?
Expand All @@ -130,6 +129,44 @@ class OauthAuthorizationServiceImpl(
clientId = data.first()
clientSecret = data.last()
}
val tOauthToken =
if (generateTokenRequest.grantType.equals(AuthorizationGrantType.AUTHORIZATION_CODE.value(), true)) {
createAuthorizationCodeToken(generateTokenRequest, clientId, clientSecret)
} else if (generateTokenRequest.grantType.equals(AuthorizationGrantType.CLIENT_CREDENTIALS.value(), true)) {
createClientCredentialsToken(clientId, clientSecret)
} else {
throw ErrorCodeException(CommonMessageCode.PARAMETER_INVALID, "grant_type")
}

val token = transfer(tOauthToken)
responseToken(token)
}

override fun refreshToken(generateTokenRequest: GenerateTokenRequest) {
with(generateTokenRequest) {
Preconditions.checkNotNull(clientId, this::clientId.name)
Preconditions.checkNotNull(refreshToken, this::refreshToken.name)
val token = oauthTokenRepository.findFirstByAccountIdAndRefreshToken(clientId!!, refreshToken!!)
?: throw ErrorCodeException(CommonMessageCode.RESOURCE_NOT_FOUND, refreshToken!!)
val idToken = generateOpenIdToken(
clientId = clientId!!,
userId = token.userId,
nonce = OauthUtils.generateRandomString(10)
)
token.accessToken = idToken.toJwtToken()
token.issuedAt = Instant.now(Clock.systemDefaultZone())
token.idToken?.let { token.idToken = idToken }
oauthTokenRepository.save(token)
responseToken(transfer(token))
}
}

private fun createAuthorizationCodeToken(
generateTokenRequest: GenerateTokenRequest,
clientId: String,
clientSecret: String?
): TOauthToken {
Preconditions.checkNotNull(generateTokenRequest.code, GenerateTokenRequest::code.name)
val code = generateTokenRequest.code!!
val userIdKey = "$clientId:$code:userId"
val openIdKey = "$clientId:$code:openId"
Expand All @@ -138,15 +175,40 @@ class OauthAuthorizationServiceImpl(
val openId = redisOperation.get(openIdKey).toBoolean()
val nonce = redisOperation.get(nonceKey)
val client = checkClientSecret(clientId, clientSecret, code, generateTokenRequest.codeVerifier)
var tOauthToken = oauthTokenRepository.findFirstByAccountIdAndUserId(clientId, userId)
val idToken = generateOpenIdToken(clientId, userId, nonce)
val tOauthToken = buildOauthToken(userId, nonce, client, openId)

userService.addUserAccount(userId, client.id!!)
return tOauthToken
}

private fun createClientCredentialsToken(
clientId: String,
clientSecret: String?
): TOauthToken {
Preconditions.checkNotBlank(clientSecret, "client_secret")
val client = accountRepository.findById(clientId)
.orElseThrow { ErrorCodeException(AuthMessageCode.AUTH_CLIENT_NOT_EXIST) }
client.credentials.find {
it.authorizationGrantType == AuthorizationGrantType.CLIENT_CREDENTIALS && it.secretKey == clientSecret
} ?: throw ErrorCodeException(AuthMessageCode.AUTH_CLIENT_NOT_EXIST)
return buildOauthToken(client.owner!!, null, client, false)
}

private fun buildOauthToken(
userId: String,
nonce: String?,
client: TAccount,
openId: Boolean
): TOauthToken {
var tOauthToken = oauthTokenRepository.findFirstByAccountIdAndUserId(client.id!!, userId)
val idToken = generateOpenIdToken(client.id, userId, nonce)
if (tOauthToken == null) {
tOauthToken = TOauthToken(
accessToken = idToken.toJwtToken(),
refreshToken = OauthUtils.generateRefreshToken(),
expireSeconds = oauthProperties.expiredDuration.seconds,
type = "Bearer",
accountId = clientId,
accountId = client.id,
userId = userId,
scope = client.scope,
issuedAt = Instant.now(Clock.systemDefaultZone()),
Expand All @@ -156,33 +218,12 @@ class OauthAuthorizationServiceImpl(
if (client.scope != tOauthToken.scope) {
tOauthToken.scope = client.scope!!
}
tOauthToken.userId = userId
tOauthToken.accessToken = idToken.toJwtToken()
tOauthToken.idToken = if (openId) idToken else null
tOauthToken.issuedAt = Instant.now(Clock.systemDefaultZone())
oauthTokenRepository.save(tOauthToken)

userService.addUserAccount(userId, client.id!!)

val token = transfer(tOauthToken)
responseToken(token)
}

override fun refreshToken(generateTokenRequest: GenerateTokenRequest) {
with(generateTokenRequest) {
Preconditions.checkNotNull(clientId, this::clientId.name)
Preconditions.checkNotNull(refreshToken, this::refreshToken.name)
val token = oauthTokenRepository.findFirstByAccountIdAndRefreshToken(clientId!!, refreshToken!!)
?: throw ErrorCodeException(CommonMessageCode.RESOURCE_NOT_FOUND, refreshToken!!)
val idToken = generateOpenIdToken(
clientId = clientId!!,
userId = token.userId,
nonce = OauthUtils.generateRandomString(10)
)
token.accessToken = idToken.toJwtToken()
token.issuedAt = Instant.now(Clock.systemDefaultZone())
token.idToken?.let { token.idToken = idToken }
oauthTokenRepository.save(token)
responseToken(transfer(token))
}
return tOauthToken
}

private fun responseToken(token: OauthToken) {
Expand Down Expand Up @@ -336,6 +377,7 @@ class OauthAuthorizationServiceImpl(
"plain" -> challenge == codeVerifier
"S256" -> Base64.getUrlEncoder().withoutPadding()
.encodeToString(HashAlgorithm.SHA256().digest(codeVerifier.orEmpty().byteInputStream())) == challenge

else -> false
}
if (!pass) {
Expand Down

0 comments on commit c0632e1

Please sign in to comment.