Scala、AkkaHttp、JsonWebToken(Jwt)を使用して認証を実装したい！パート1

この記事は認証認可あたりを聞いたことはあるけど、実装はしたことないって人向けです。

具体的にどのようにJwtを発行したり、デコードするかは「Jwt 仕組み」とかでググってもらえるとわかるとおもいます。


#正しいリクエストなのかどうやって認証するか？

認証の仕組みとしては、
<img width="631" alt="スクリーンショット 2018-10-25 15.49.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/211255/57e00c8a-f347-1417-c1aa-3b9db07411eb.png">
こんな風にRequestのHeaderに格納されているJsonWebTokenをAppサーバー側で、正しくデコードできればそのユーザーは正規のユーザーであると認証する感じです。

#RequestHeaderからアクセストークン(String)を取得！

最初はRequestHeaderに入っている

<img width="941" alt="スクリーンショット 2018-10-25 15.55.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/211255/4edf790b-3412-c18f-53be-ae6233bf0969.png">
の部分を

```ruby:qiita.scala
val validateCustomHeader: Directive1[String] = {
    val value = headerValueByName("Authorization")
    value.filter(_ == "Bearer [Jwtトークン部分]" ,MalformedHeaderRejection("Authorization", "value was wrong"))
}
```


と、AkkaのRouteを使ってリクエストの認証を行おうと思ったんですが、
valueのfilterの_ == "Bearer ~~~~~~~~~~"部分をどうもうまく拡張できない。

value.filter(_ => (jwtの有効性をチェックするBoolean))とかで書けると思ったんですが、型的にoutでした。(かなしい)

なので、別のアプローチから実装することに。

#SecurityDirectivesで取得してみる

SecurityDirectivesの中身を見てたら便利そうなのを発見

```ruby:qiita.scala
  def authenticateOAuth2Async[T](realm: String, authenticator: AsyncAuthenticator[T]): AuthenticationDirective[T] =
    extractExecutionContext.flatMap { implicit ec ⇒
      def extractAccessTokenParameterAsBearerToken = {
        import akka.http.scaladsl.server.Directives._
        parameter('access_token.?).map(_.map(OAuth2BearerToken))
      }
      val extractCreds: Directive1[Option[OAuth2BearerToken]] =
        extractCredentials.flatMap {
          case Some(c: OAuth2BearerToken) ⇒ provide(Some(c))
          case _                          ⇒ extractAccessTokenParameterAsBearerToken
        }
      extractCredentialsAndAuthenticateOrRejectWithChallenge[OAuth2BearerToken, T](extractCreds, { cred ⇒
        authenticator(Credentials(cred)).fast.map {
          case Some(t) ⇒ AuthenticationResult.success(t)
          case None    ⇒ AuthenticationResult.failWithChallenge(HttpChallenges.oAuth2(realm))
        }
      })
    }
```
なんかOAuth2BearerTokenをうまく扱えそう＾＾


```ruby:qiita.scala
val extractCreds: Directive1[Option[OAuth2BearerToken]] =
  extractCredentials.flatMap {
    case Some(c: OAuth2BearerToken) ⇒ provide(Some(c))
    case _                          ⇒ extractAccessTokenParameterAsBearerToken
  }
```

ここの部分でHeaderのAuthorizationの部分をStringからOAuth2BearerTokenにしてSome(c)に格納してるみたいですね。

さらに下の

```ruby:qiita.scala
        authenticator(Credentials(cred)).fast.map {
          case Some(t) ⇒ AuthenticationResult.success(t)
          case None    ⇒ AuthenticationResult.failWithChallenge(HttpChallenges.oAuth2(realm))
        }
```
の部分で引数のauthenticatorにCredentials(cred)の形で渡しているので、ここを追ってみると
最終的に

```ruby:qiita.scala
  override def authenticate(credentials: Credentials): Future[Option[AuthContext]] = {
       ~~~~ここでJwt認証の実装をする ~~~~~
  }
```

って形で、authenticatorを実装すれば認証機能が作れそうです。

つまり

```ruby:qiita.scala
a: Future[Option[AuthContext]] match {
  Some(t) => 認証成功
  None => 認証失敗
}
```

となるわけですね

#Authenticatorを実装してみる

authenticator(Credentials(cred))とあるので、HeaderのAuthorization部分の取得を１から書く必要はなさそう。

```ruby:qiita.scala
  override def authenticate(credentials: Credentials): Future[Option[AuthContext]] = {
    credentials match {
      case Credentials.Provided(jwt) => validateJwt(jwt)
      case _ => Future { None }
    }
  }
```

と簡単に書いちゃいましょう。これでjwtがString形式で受け取れるようになりました。

というわけで次回は、Jwtのデコードをしていこうと思います。

パート２ -> https://qiita.com/katokonn1020/items/44ff9a6bec7967358b1d