Kotlin OAuth在Ktor中使用Keyclope:它应该像这样工作吗?
我试图在Ktor web服务器中通过KeyClope设置一个工作的Oauth2授权。预期的流程是从web服务器向Key斗篷发送请求并登录到给定的UI,然后Key斗篷发回可用于接收令牌的代码。像 首先,我是根据Ktor文档中的示例来做的。它工作得很好,直到我必须接收令牌,然后它只给我HTTP状态401。即使curl命令工作正常。然后我尝试了一个我在上找到的示例项目,我通过构建自己的HTTP请求并将其发送到KeyClope服务器以接收令牌来实现它,但它应该是这样工作的吗 关于这一点,我有很多问题Kotlin OAuth在Ktor中使用Keyclope:它应该像这样工作吗?,kotlin,authentication,oauth-2.0,keycloak,ktor,Kotlin,Authentication,Oauth 2.0,Keycloak,Ktor,我试图在Ktor web服务器中通过KeyClope设置一个工作的Oauth2授权。预期的流程是从web服务器向Key斗篷发送请求并登录到给定的UI,然后Key斗篷发回可用于接收令牌的代码。像 首先,我是根据Ktor文档中的示例来做的。它工作得很好,直到我必须接收令牌,然后它只给我HTTP状态401。即使curl命令工作正常。然后我尝试了一个我在上找到的示例项目,我通过构建自己的HTTP请求并将其发送到KeyClope服务器以接收令牌来实现它,但它应该是这样工作的吗 关于这一点,我有很多问题 这
authenticate(keycloakOAuth) {
get("/oauth") {
val principal = call.authentication.principal<OAuthAccessTokenResponse.OAuth2>()
call.respondText("Access Token = ${principal?.accessToken}")
}
}
get("/token"){
var grantType = "authorization_code"
val code = call.request.queryParameters["code"]
val requestBody = "grant_type=${grantType}&" +
"client_id=${keycloakProvider.clientId}&" +
"client_secret=${keycloakProvider.clientSecret}&" +
"code=${code.toString()}&" +
"redirect_uri=http://localhost:8080/token"
val tokenResponse = httpClient.post<HttpResponse>(keycloakProvider.accessTokenUrl) {
headers {
append("Content-Type","application/x-www-form-urlencoded")
}
body = requestBody
}
call.respondText("Access Token = ${tokenResponse.readText()}")
}
get(“/token”){
var grantType=“授权\代码”
val code=call.request.queryParameters[“code”]
val requestBody=“grant_type=${grantType}&”+
“客户端\u id=${keydeposeprovider.clientId}&”+
“客户端_secret=${keydeposeprovider.clientSecret}&”+
“code=${code.toString()}&”+
"重定向"uri=http://localhost:8080/token"
val tokenResponse=httpClient.post(keydeposeprovider.accessTokenUrl){
标题{
追加(“内容类型”、“应用程序/x-www-form-urlencoded”)
}
body=requestBody
}
call.respondText(“访问令牌=${tokenResponse.readText()}”)
}
TL;DR:我可以通过KeyClope登录,但尝试获取访问令牌会给我401。ktor中的authenticate函数也应该处理这个问题吗?第一个问题的答案是:如果该路由对应于在
urlProvider
lambda中返回的重定向URI,那么它将同时用于这两个问题
整个过程如下:
认证下的任何路由)
authorizeUrl
传递必要的参数urlProvider
lambda提供的重定向URI,并传递获取访问令牌所需的参数OAuthAccessTokenResponse
对象,该对象具有访问令牌、刷新令牌和从KeyClope返回的任何其他参数的属性val provider = OAuthServerSettings.OAuth2ServerSettings(
name = "keycloak",
authorizeUrl = "http://localhost:8080/auth/realms/master/protocol/openid-connect/auth",
accessTokenUrl = "http://localhost:8080/auth/realms/$realm/protocol/openid-connect/token",
clientId = clientId,
clientSecret = clientSecret,
requestMethod = HttpMethod.Post // The GET HTTP method is not supported for this provider
)
fun main() {
embeddedServer(Netty, port = 7777) {
install(Authentication) {
oauth("keycloak_oauth") {
client = HttpClient(Apache)
providerLookup = { provider }
// The URL should match "Valid Redirect URIs" pattern in Keycloak client settings
urlProvider = { "http://localhost:7777/callback" }
}
}
routing {
authenticate("keycloak_oauth") {
get("login") {
// The user will be redirected to authorizeUrl first
}
route("/callback") {
// This handler will be executed after making a request to a provider's token URL.
handle {
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
if (principal != null) {
val response = principal as OAuthAccessTokenResponse.OAuth2
call.respondText { "Access token: ${response.accessToken}" }
} else {
call.respondText { "NO principal" }
}
}
}
}
}
}.start(wait = false)
}
val provider=OAuthServerSettings.OAuth2ServerSettings(
name=“keydeave”,
授权URL=”http://localhost:8080/auth/realms/master/protocol/openid-连接/验证“,
accessTokenUrl=”http://localhost:8080/auth/realms/$realm/protocol/openid connect/token“,
clientId=clientId,
clientSecret=clientSecret,
requestMethod=HttpMethod.Post//此提供程序不支持GET-HTTP方法
)
主要内容(){
嵌入式服务器(网络,端口=7777){
安装(身份验证){
oauth(“keydove_oauth”){
client=HttpClient(Apache)
providerLookup={provider}
//URL应与KeyClope客户端设置中的“有效重定向URI”模式匹配
urlProvider={”http://localhost:7777/callback" }
}
}
路由{
验证(“keydove_oauth”){
获取(“登录”){
//用户将首先被重定向到authorizeUrl
}
路由(“/callback”){
//此处理程序将在向提供者的令牌URL发出请求后执行。
处理{
val principal=call.authentication.principal()
if(主体!=null){
val response=主体作为OAuthAccessTokenResponse.OAuth2
call.respondText{“访问令牌:${response.accessToken}”}
}否则{
call.respondText{“无主体”}
}
}
}
}
}
}.start(等待=false)
}
val provider = OAuthServerSettings.OAuth2ServerSettings(
name = "keycloak",
authorizeUrl = "http://localhost:8080/auth/realms/master/protocol/openid-connect/auth",
accessTokenUrl = "http://localhost:8080/auth/realms/$realm/protocol/openid-connect/token",
clientId = clientId,
clientSecret = clientSecret,
requestMethod = HttpMethod.Post // The GET HTTP method is not supported for this provider
)
fun main() {
embeddedServer(Netty, port = 7777) {
install(Authentication) {
oauth("keycloak_oauth") {
client = HttpClient(Apache)
providerLookup = { provider }
// The URL should match "Valid Redirect URIs" pattern in Keycloak client settings
urlProvider = { "http://localhost:7777/callback" }
}
}
routing {
authenticate("keycloak_oauth") {
get("login") {
// The user will be redirected to authorizeUrl first
}
route("/callback") {
// This handler will be executed after making a request to a provider's token URL.
handle {
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
if (principal != null) {
val response = principal as OAuthAccessTokenResponse.OAuth2
call.respondText { "Access token: ${response.accessToken}" }
} else {
call.respondText { "NO principal" }
}
}
}
}
}
}.start(wait = false)
}