この記事で説明すること
spring-boot, spring-security, spring-socialを使ってソーシャルログインを実装したので、そのサンプルを利用してどのように実装したかを解説します。長くなると思うので自分が興味のあるChapterだけ選んで読んでみてください。
今回のサンプルでは、ソーシャルログインだけでなく、userid/passwordを入力してログインすることもできます。
経緯
spring-bootやspring-securityははじめてのSpring Bootで勉強した。
この本では、spring-boot, securityを使って、ログイン/ログアウトができる名簿アプリを作るのだが、そこに 「Sign in with Twitter」の機能も付けたくなり、つけようとしたが思いの外苦労してしまった…
私はこの苦労をこの世から根絶すべく、当記事の執筆に踏み切ったのである。
サンプルについて
ソースコード
こちらです。 https://github.com/PonzyPon/spring-boot-social-demo
サンプル君のできること
- 独自のID/Passwordでログインできます
- Twitterでログインできます
- Twitterでログインした際にそれがそのユーザーにとって初めてのログインだった場合、裏で暗黙的にユーザー登録をします
- ログインしたら、画面左上にそのユーザーの名前を表示できます
- サーバー側ロジックで現在ログイン中のユーザーのUserIdを取得できます
UserContext#getUserId
サンプル君のできないこと
- ユーザー登録機能は実装していません。あらかじめ
V1__create-tables.sqlにてuser1というサンプルユーザーを作成しています
サンプル君のDB設計
このサンプルでは、独自ID/Passwordでのログインと、ソーシャルログインのどちらもを実現したかった。そのため2つのテーブルを作成した。ユーザーのマスタであるUserテーブルと、ソーシャルログイン情報を保持するUserConnectionテーブルである。User#user_idとUserConnection#userIdは同じ物。この値を使って連結する。
User テーブル
| カラム | 型 | 補足 |
|---|---|---|
| user_id | VARCHAR | primary key |
| username | VARCHAR | これもUNIQUE。 ログイン時にユーザーが入力する |
| display_name | VARCHAR | |
| encoded_password | VARCHAR |
UserConnection テーブル
| カラム | 型 |
|---|---|
| userId | VARCHAR |
| providerId | VARCHAR |
| providerUserId | VARCHAR |
| rank | INT |
| displayName | VARCHAR |
| profileUrl | VARCHAR |
| imageUrl | VARCHAR |
| accessToken | VARCHAR |
| secret | VARCHAR |
| refreshToken | VARCHAR |
| expireTime | BIGINT |
このUserConnectionテーブルだが、実はもうこの構成はほぼ固定。このテーブルを操作するソースコードは自分では全く書いておらず、全てspring任せ。spring-frameworkにこんな感じでsqlのサンプルが提供されている。コピペして使おう。
ソースコード解説
spring-securityとspring-socialを使っている中でよく分からないのが**俺の責務はどこだ?**ということ。つまり、**springがやってくれる部分と自分がやるべき部分との境界が分かりにくい。**なのでその辺を含めて解説していく。
処理フローとその責任者
ユーザーログイン
UserをDBからロードする部分はspringはやってくれない。だからそこはUserDetailServiceというInterfaceを実装する必要がある。そうしておけば、その実装クラスが勝手に呼ばれてspringがUserのロード処理を行ってくれる。
UserDetailsServiceImplのソースはこちら
ソーシャルログイン
ソーシャルログインの場合は、SNSアカウント情報を保持しているUserConnectionテーブルに対しての存在確認や、データの登録が必要となる。ただし、これは全てspringがやってくれる。我々開発者は、Userの作成処理と、そのUserテーブルからのロード処理をやってやればよい。
ConnectionSignUpImplのソースはこちら
SocialUserDetailsServiceImplのソースはこちら
その他のクラス
SignupServiceとUserContextは必須ではない
基本的には最小構成でソーシャルログインのサンプルを作成しようとしているので、不要なクラスは無いが、例えばSignupServiceは作成しなくてもよい。このInterfaceは自分で作成したものだし、SignupServiceImpl#createUserの処理はConnectionSignUpImpl#executeに書いてしまってもよい。今回は、今後ユーザーの登録機能が付けば別クラスに分けることになるだろうと思ってクラスを分けただけ。
また、UserContextはログインユーザーのuserIdを簡単に取得できるよう作った便利クラス。無くてもソーシャルログインは動作する。
springの設定はSecurityConfigで
上でusernameとpasswordを受け取って認証する処理はspring任せという話をしたが、その設定はSecurityConfigで行っている。
解説はここまで。ここから下はサンプルの動かし方やいじくり方を説明します。
サンプル君の動かし方
(自分のtwitterアプリのConsumer KeyとConsumer Secretがある方は3から)
-
twitter でアプリを登録する (https://apps.twitter.com/)
こんな感じで入力してください。

-
アプリをCreateしたら、twitter アプリの
Consumer KeyとConsumer Secretを( ..)φメモメモしておく

-
git clone https://github.com/PonzyPon/spring-boot-social-demo.git
-
src/main/resources以下のapplication.properties.sampleをコピーしてapplication.propertiesを作る
-
application.properties内の
spring.social.twitter.app-idとspring.social.twitter.app-secretにそれぞれ上で( ..)φメモメモしたConsumer KeyとConsumer Secretを書く -
プロジェクトのルート(pom.xmlがある場所)で
mvnw spring-boot:runを実行する(mavenインストール済の人はmvn spring-boot:runでOK) -
localhost:7000にアクセスする
-
(*^-^*)
(※もし、Twitterログイン時にエラーが出たらまずはTwitterアプリのCallback URL LockedをNoにしてみてください。それでダメならググって解決するしかないのです(^○^))
サンプル君のいじり方
Twitterでログインした後ツイートしたい
HomeController#writeTweetIdIfLoggedInWithTwitterというメソッドをデモ用に作成してあり、もしTwitterでログインしている場合は、そのアカウントのタイムラインの最新のつぶやきのtweetIdを取得しコンソールに書き出している。ここで使われているtwitter変数を使えばつぶやきも可能なのだ。サンプルとしてソースに書いてあるのでコメントアウトして試してみてほしい
// Hello!! とツイートする
twitter.timelineOperations().updateStatus("Hello!!");
現在ログインしているユーザーのIDを取得したい
UserContext#getUserIdを呼び出してくれ。誰もログインしていない場合もあるから、戻り値はOptional<String>だ。使うときはこんなイメージ。
public class Sample {
@Autowired
private final UserContext userContext;
public Data getData() {
dao.getData(userContext.getUserId().get());
}
}
おわりに
このサンプルを作る前の自分が見たら嬉しくなるような記事をイメージして書きました。もし間違っているところや意見・質問あればよろしくお願いします。以上です。

