简体   繁体   中英

Akka Authentication with REST Http

I'm testing Json HTTP Routes with Akka Basic Authentication and scala. But the routes don't work as needed. Here is the code

First the secured route is not working with postman BasicAuth. I need to add an email"secured/test@test.com" to trigger the logged in action. Second the subroute basketactor is not working at all. Postman says unknown Route. So how can i make this work with Postman BasicAuth Http Header? What kind of request do i have to send just "secured or with email and password together. Second how can i make the subroutes basketActor/add work.

~ Route.seal {
          (pathPrefix("secured") & get) {
            authenticateBasic(realm = "secure site", myUserPassAuthenticator) { email =>
              path(Segment) { segment =>
                var user = User.USER_LIST.find(_.id == segment)
                if (user.isDefined)
                  complete(s"Hi '$email' you logged in")
                else complete(s"login failed Please register at ${"users" / "register"}")
              }
            } ~ path("basketActor") {
              (pathEnd & get) {
                implicit val timeout = Timeout(3 seconds)
                onSuccess((basketActor ? GetBasketProducts).mapTo[BasketList]) { res =>
                  complete(BasketContainer(products = res.products))
                }
              } ~ (path("add" / IntNumber) & post) { number =>
                val product = Product.PRODUCT_LIST.find(_.id == number)
                if (product.isDefined) {
                  product.foreach { product =>
                    basketActor ! AddProductToBasket(product)
                    //            complete(Basket.BASKET_LIST ::= product)
                  }
                  complete(product)
                } else complete("Not found")
              }
            }
          }
      }
 def myUserPassAuthenticator(credentials: Credentials): Option[String] =
      credentials match {
        case p@Credentials.Provided(id) if p.verify("secret") => Some(id)
        case _ => None
      }

So my expected result should be the user calls the secured Route logs in and then he can access the basketActor route. But now the route is not accessible and the secured route is also not working

This is how Basic Authentication works in Akka HTTP:

The Authorization header in an HTTP Request is used for Basic Authentication, and it contains a username and password encoded using base64 encoding. The authenticateBasic route will extract this information from the header to create a Credentials object, and then pass this to your myUserPassAuthenticator method. This method should check that the username and password match and if it succeeds it should return an object representing that user in your system, or return None on failure.

The second (curried) argument to authenticateBasic is a function that takes the user data and returns a Route . So in your case the email argument will contain the id value returned by myUserPassAuthenticator . This function should return a route that contains all the paths that require authentication.


It is important to realise that there is no concept of being "logged in" with Basic Authentication. There are just authentication credentials that are either correct or incorrect. (If you want to have login/logout semantics you need to move to a token-based authentication mechanism).


So to make your routes work you need to move the logic that looks-up a user ID into myUserPassAuthenticator and return the user object as the result. As it happens you can just return the result of find because this already returns an Option[User] .

You also need to make sure that all the authenticated routes are inside the authenticateBasic route. Currently the basketActor and add routes are at the same level and therefore are not authenticated.


A sample route would look like this. I have used concat rather than ~ as I think it is clearer.

pathPrefix("secured") {
  authenticateBasic(realm = "secure site", myUserPassAuthenticator) { user =>
    concat(
      (pathEnd | pathSingleSlash) {
        get {
          complete(s"User $user Authenticated OK")
        }
      },
      path("basketActor") {
        (pathEnd & get) {
          complete(s"basketActor for $user")
        }
      },
      path("add" / IntNumber) { number =>
        post {
          complete(s"User $user posted $number")
        }
      }
    )
  }
}

Note that the user ID (email address) is not in the URL, it is in the request in the Basic Authentication header.

To test this with Postman you need to go create a GET with the URL .../secured or .../secured/basketActor , or a POST with the URL .../secured/add/1 . Under the Auth tab you need to select Basic Authentication and add the credentials there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM