Ktor测试路由与 ‘authenticate(){}’

huangapple go评论150阅读模式
英文:

Ktor testing routes with 'authenticate(){}'

问题

以下是代码部分的翻译:

  1. fun Application.install() {
  2. routing {
  3. route("point") {
  4. authenticate(AUTH_SESSION) {
  5. post("/test") { testController.test(context) }
  6. }
  7. }
  8. }
  9. }
  1. @Test
  2. fun `test auth route`() = testApplication {
  3. val client = client()
  4. client.post("/point/test")
  5. }

请注意,我已经删除了HTML编码字符(")并将其替换为普通引号。如果您需要其他内容的翻译,请提供相关文本。

英文:

What is the appropriate way of unit testing such routes?

  1. fun Application.install() {
  2. routing {
  3. route("point") {
  4. authenticate(AUTH_SESSION) {
  5. post("/test") { testController.test(context) }
  6. }
  7. }
  8. }
  9. }

The problem is such routes require auth info. This code results in 401 error:

  1. @Test
  2. fun `test auth route`() = testApplication {
  3. val client = client()
  4. client.post("/point/test")
  5. }

I use GoogleOneTap auth for a mobile application. From GoogleOneTap jwt token I generate User session with a Bearer. That session expires after some time.
So, such a test user requires manual auth each time session expires? If so, it's not appropriate for a CI.

Should I implement a simple auth with user-password and call auth before each call under authenticate(AUTH_SESSION)?

答案1

得分: 0

这是你要翻译的内容的翻译部分:

  1. Finally, I got it:
  2. 1) Read through ktor docs https://ktor.io/docs/testing.html
  3. 1) With any auth you have auth route: `post("/auth/myprovider")` which gives you bearer cookie
  4. Your routing:
  5. ```kotlin
  6. routing {
  7. // auth route to get a bearer cookie
  8. post("/auth/google") { googleAuthController.signIn(context) }
  9. authenticate(AUTH_SESSION) {
  10. // these routes need auth bearer cookie
  11. post("/my/route/requiring/auth")
  12. }
  13. }

post("/my/route/requiring/auth") uses authentication, hence all testing requests have to have auth bearer cookie. To get it, create a separate test user with test credentials:

  1. class GoogleAuthController(
  2. private val userDao: UserDao
  3. ) {
  4. suspend fun signIn(call: ApplicationCall) {
  5. val token = call.parameters["token"]!!
  6. val userInfo: UserInfo? = verifyTestUsers(token) ?: GoogleAuthVerifier.verify(token)
  7. if (userInfo != null) {
  8. // create user
  9. val userSession = UserSession(
  10. id = userInfo.id,
  11. email = userInfo.email,
  12. name = userInfo.name,
  13. pictureUrl = userInfo.pictureUrl,
  14. locale = userInfo.locale
  15. )
  16. // save user to db
  17. userDao.saveUserInfoGoogleOneTap(userSession)
  18. // set user cookie
  19. call.sessions.set(userSession)
  20. call.respond(HttpStatusCode.OK)
  21. } else {
  22. throw IllegalArgumentException("Invalid token")
  23. }
  24. }
  25. // testUsers: Map<String, UserInfo>;
  26. private fun verifyTestUsers(token: String): UserInfo? = testUsers[token]
  27. }

Basically, this is how you can get a cookie for any of your test users.

Next, to make calls, you need a client:

  1. suspend fun ApplicationTestBuilder.myAuthClient(token: String = testUserToken) = createClient {
  2. install(HttpCookies)
  3. install(ContentNegotiation) {
  4. json(Json {
  5. prettyPrint = true
  6. isLenient = true
  7. ignoreUnknownKeys = true
  8. encodeDefaults = true
  9. })
  10. }
  11. }.also {
  12. it.post("/auth/google") {
  13. parameter("token", token)
  14. }
  15. }

Here on each client creation you call your auth method and get credentials for a test user.

Now you are ready to make authenticated calls:

  1. internal class TestAuth {
  2. @Test
  3. fun `test auth`() = testApplication {
  4. val client = myAuthClient()
  5. // here `client` already has a Bearer cookie
  6. val response = client.post("/my/route/requiring/auth")
  7. assert(response.body<String>().isNotEmpty())
  8. }
  9. }

希望这些翻译对你有所帮助。

英文:

Finally, I got it:

  1. Read through ktor docs https://ktor.io/docs/testing.html
  2. With any auth you have auth route: post(&quot;/auth/myprovider&quot;) which gives you bearer cookie

Your routing:

  1. routing {
  2. // auth route to get a bearer cookie
  3. post(&quot;/auth/google&quot;) { googleAuthController.signIn(context) }
  4. authenticate(AUTH_SESSION) {
  5. // these routes need auth bearer cookie
  6. post(&quot;/my/route/requiring/auth&quot;)
  7. }
  8. }

post(&quot;/my/route/requiring/auth&quot;) uses authentication, hence all testing requests have to have auth bearer cookie. To get it, create a separate test user with test credentials:

  1. class GoogleAuthController(
  2. private val userDao: UserDao
  3. ) {
  4. suspend fun signIn(call: ApplicationCall) {
  5. val token = call.parameters[&quot;token&quot;]!!
  6. val userInfo: UserInfo? = verifyTestUsers(token) ?: GoogleAuthVerifier.verify(token)
  7. if (userInfo != null) {
  8. // create user
  9. val userSession = UserSession(
  10. id = userInfo.id,
  11. email = userInfo.email,
  12. name = userInfo.name,
  13. pictureUrl = userInfo.pictureUrl,
  14. locale = userInfo.locale
  15. )
  16. // save user to db
  17. userDao.saveUserInfoGoogleOneTap(userSession)
  18. // set user cookie
  19. call.sessions.set(userSession)
  20. call.respond(HttpStatusCode.OK)
  21. } else {
  22. throw IllegalArgumentException(&quot;Invalid token&quot;)
  23. }
  24. }
  25. // testUsers: Map&lt;String, UserInfo&gt;
  26. private fun verifyTestUsers(token: String): UserInfo? = testUsers[token]
  27. }

Basically, this is how you can get a cookie for any of your test users.

Next, to make calls, you need a client:

  1. suspend fun ApplicationTestBuilder.myAuthClient(token: String = testUserToken) = createClient {
  2. install(HttpCookies)
  3. install(ContentNegotiation) {
  4. json(Json {
  5. prettyPrint = true
  6. isLenient = true
  7. ignoreUnknownKeys = true
  8. encodeDefaults = true
  9. })
  10. }
  11. }.also {
  12. it.post(&quot;/auth/google&quot;) {
  13. parameter(&quot;token&quot;, token)
  14. }
  15. }

Here on each client creation you call your auth method and get credentials for a test user.

Now you are ready to make authenticated calls:

  1. internal class TestAuth {
  2. @Test
  3. fun `test auth`() = testApplication {
  4. val client = myAuthClient()
  5. // here `client` already has a Bearer cookie
  6. val response = client.post(&quot;/my/route/requiring/auth&quot;)
  7. assert(response.body&lt;String&gt;().isNotEmpty())
  8. }
  9. }

huangapple
  • 本文由 发表于 2023年2月19日 15:32:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/75498620.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定