タイトルの通り、いわゆる「LINEでログイン」を試してみた時のメモ。
ソースコード
koirand/springboot-line-login: LINE login with Springboot Sample
OAuth2での認証方法
第1回:Spring Security 5でサポートされるOAuth 2.0 LoginをSpring Bootで使ってみる
主にこの記事にOAuth2クライアントの実装を行った。OAuth2でログインするためには、spring-security-oauth2-clientモジュールを使う。OpenID Connectでの認証を行う場合は加えてspring-security-oauth2-joseが必要になるが、今回はOAuth2のみなので入れなかった。
<!-- OAuth2 authentication-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
application.properties に以下の通りLINE用の設定を記載する。clientID
とclientSeret
はLINE Developersで取得したものに書き換える。
# Settings for LINE login
spring.security.oauth2.client.registration.line.clientId={Set your client id}
spring.security.oauth2.client.registration.line.clientSecret={Set your client secret}
spring.security.oauth2.client.registration.line.authorizationGrantType=authorization_code
spring.security.oauth2.client.registration.line.redirectUriTemplate={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.line.scope=profile
spring.security.oauth2.client.registration.line.clientName=LINE
spring.security.oauth2.client.provider.line.authorizationUri=https://access.line.me/oauth2/v2.1/authorize
spring.security.oauth2.client.provider.line.tokenUri=https://api.line.me/oauth2/v2.1/token
spring.security.oauth2.client.provider.line.jwkSetUri=https://api.line.me/oauth2/v2.1/verify
spring.security.oauth2.client.provider.line.userInfoUri=https://api.line.me/v2/profile
spring.security.oauth2.client.provider.line.userNameAttribute=userId
Spring Securtyでは、GitHub、Google、Facebook、Oktaの4つのプロバイダに関しては、各設定値の初期値が既に設定されている。なのでapploication.propatiesにはclientId
とclientSecret
だけを設定すれば動作する。例えばGitHubを追加するなら、以下の設定を追加するだけで良い。
# Settings for GitHub login
spring.security.oauth2.client.registration.github.clientId={Set your client id}
spring.security.oauth2.client.registration.github.clientSecret={Set your client secret}
LINEは初期値が設定されていないので全ての設定が必要になる。scopeの種類や、各エンドポイントのURI、APIの仕様などは以下を参照。
LINEの場合、ユーザープロファイルを取得するためのAPI(userInfoUriで指定しているエンドポイント)のレスポンスが以下のようなJSONになる。従ってuserNameAttribute
には、ユーザー名に該当するuserIdを指定している。
{
"userId":"U4af4980629...",
"displayName":"Brown",
"pictureUrl":"https://example.com/abcdefghijklmn",
"statusMessage":"Hello, LINE!"
}
ちなみにSpringboot v2.1.0.M2より古いバージョンは、userNameAttribute
が反映されないので注意されたし。
コントローラーのメソッドの引数に@AuthenticationPrincipal
を指定することで、認証済みのユーザーの情報を受け取ることができるようになる。ここではシンプルにユーザー情報をレスポンスボディにそのままセットしている。
package com.example;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
@RestController
public class SampleController {
@GetMapping("/")
public Object index(@AuthenticationPrincipal OAuth2User oauth2User) {
return oauth2User;
}
}
http://localhost:8080
にアクセスすると、未認証の場合は、/login
にリダイレクトされる。/login
エンドポイントを実装していなければ、Spring SecurityのDefaultLoginPageGeneratingFilterが以下のログイン画面を自動生成する仕組みになっている。
この例ではLINEのみだが、複数のプロバイダを設定した場合はそれぞれのリンクが表示される。LINEリンクをクリックすると、http://localhost:8080/oauth2/authorization/line
に遷移する。自前のログインページを作成する場合は同じようにこのURIへ遷移するリンクなりボタンを作成すれば良い。http://localhost:8080/oauth2/authorization/line
にアクセスすると、そこから更にauthorizationUri
で設定したhttps://access.line.me/oauth2/v2.1/authorize
へリダイレクトしてLINEの認証画面が表示される。認証に成功すると、http://localhost:8080/login/oauth2/code/line
へリダイレクトし、そして最初にアクセスしたhttp://localhost:8080
へリダイレクトする。まとめると以下のようなページ遷移になる。
http://localhost:8080
↓ リダイレクト
http://localhost:8080/login
↓ リンクをクリック
http://localhost:8080/oauth2/authorization/line
↓ リダイレクト
https://access.line.me/oauth2/v2.1/authorize
↓ 認証成功
http://localhost:8080/login/oauth2/code/line
↓ リダイレクト
http://localhost:8080
なお、認証成功時のリダイレクト先のURLについては、LINE Developer画面上でホワイトリストに設定しておく必要がある。LINE以外の他のプロバイダでも同様。
別の実装方法
LINE Engieeringブログで、spring-boot-starter-security
とspring-security-oauth
を使った実現方法が紹介されていたが、この方法だとOAuth2プロバイダが1つしか指定できなかったので採用しなかった。実際はLINEだけでなくGoogleやFacebookと併用したいケースが多いのではないだろうか。
Spring Security + 設定ファイルで始める LINE との ID Federation : LINE Engineering Blog