🔖
Re:ゼロから始めるSpring Boot実践#1 WebBlog開発#3 ユーザログイン
機能一覧※再掲
- ユーザ
1.1 新規登録
1.2 ログイン ← 本記事の内容
1.3 ユーザ情報取得
1.4 ユーザ情報更新
1.5 アバター画像変更
1.6 パスワード変更 - 記事カテゴリ
略 - 記事管理
略
API設計
1.2 ログイン
1.2.1 基本情報
リクエストパス:
/user/login
リクエスト方式:POST
インターフェース概要:このインターフェースはログインに使用される。
1.2.2 リクエストパラメータ
リクエストパラメータ形式:x-www-form-urlencoded
リクエストパラメータ説明:
| パラメータ名 | 説明 | 型 | 必須 | 備考 |
|---|---|---|---|---|
| username | ユーザー名 | string | 必須 | 5~16文字の非空文字列 |
| password | パスワード | string | 必須 | 5~16文字の非空文字列 |
リクエストデータ例:
username=zhangsan&password=123456
1.2.3 レスポンスデータ
-
レスポンスデータタイプ:
application/json -
レスポンスパラメータ説明:
| 項目名 | 型 | 必須 | デフォルト値 | 説明 | その他情報 |
|---|---|---|---|---|---|
| code | number | 必須 | - | レスポンスコード、0-成功、1-失敗 | |
| message | string | 任意 | - | メッセージ情報 | |
| data | string | 必須 | - | レスポンスデータ、JWTトークン |
- レスポンスデータ例:
{
"code": 0,
"message": "操作成功",
"data": "ここはJWTが入る想定"
}
1.2.4 備考
ユーザーがログインに成功すると、システムは自動的にJWTトークンを発行。以後、すべてのリクエストでは、ブラウザがリクエストヘッダー(
Authorization)にこのJWTトークンを付与してサーバに送信する必要がある。
ユーザーが未ログインの場合、HTTPレスポンスステータスコードは401となる。
API開発
1. 開発するメソッド・クラスを考える
1.1 ユーザログイン機能
- UserControllerにloginメソッドを作成し以下の機能を提供
(1). ユーザー名を用いてユーザを検索
(2). ユーザが存在するかを判断
(3). 入力PWが正しいかを判断 - UserviceにfindeByUsernameメソッドを作成し以下の機能を提供
(1). ユーザー名を用いてユーザを検索 - UserMapperにユーザ名検索メソッドを作成以下のsql文を発行
(1). select * from user where username=?;
1.2 ログインステータスの検証
-
実現したいこと:
(1). ログインしていない状態で、新規登録とログインAPIのみアクセス可能。
(2). ログインしている状態で、上記2つAPI以外のAPIにアクセス可能。
よって、JWT認証と用いたログインステータスを検証する共通機能を作成する。
参考:https://qiita.com/asagohan2301/items/cef8bcb969fef9064a5c -
実装方法:
(1). Interceptorを使ってAPI実行前にログインステータスを検証する共通処理を実行
(2). /user/login と /user/register パスは除外
2. ログインステータスを検証する機能を作成
2.1 JWT生成・取得のメソッド
public class JwtUtil {
//暗号キーを設定
private static final String KEY = "rezerosb";
//リクエストデータを受け取ってトークンを生成して返す。
public static String genToken(Map<String, Object> claims) {
return JWT.create()
.withClaim("claims", claims)
.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 *12 )) //有効期間を設定
.sign(Algorithm.HMAC256(KEY));
}
//トークンを受け取って検証した後、リクエストデータを返す。
public static Map<String, Object> parseToken(String token) {
return JWT.require(Algorithm.HMAC256(KEY))
.build()
.verify(token)
.getClaim("claims")
.asMap();
}
}
2.2 ログインステータスを検証するメソッド
@Component //自動でインスタンス化し、他クラスに注入できるようにするため。
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
//tokenを検証
String token = request.getHeader("Authorization");
System.out.println(token);
try {
Map<String, Object> claims = JwtUtil.parseToken(token);
return true;
} catch (Exception e) {
//httpステータスコード401
response.setStatus(401);
return false;
}
}
}
2.3 InterceptorをSpringの処理フローに追加
@Configuration //LoginInterceptorをSpring MVCの処理の流れに追加するため。
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry){
//ユーザ登録とユーザログインを対象外とする。
registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
}
}
3. Controllerの作成
UserControllerクラスに以下のメソッドを追加
@PostMapping("/login")
public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password) {
//(1). ユーザー名を用いてユーザを検索
User loginUser = userService.findByUserName(username);
//(2). ユーザが存在するかを判断
if (loginUser == null) {
return Result.error("ユーザ名は存在しません。");
}
//(3). 入力PWが正しいかを判断
if (Md5Util.getMD5String(password).equals(loginUser.getPassword())){
//JWT生成
Map<String, Object> claims = new HashMap<>();
claims.put("id",loginUser.getId());
claims.put("username",loginUser.getUsername());
String token = JwtUtil.genToken(claims);
System.out.println(token);
return Result.success(token);
}
return Result.error("パスワードは正しくありません。");
}
4. Seriveの作成
UserServiceImplには、findByUserNameメソッドはは作成済みのため作業不要。
4 Mapperの開発
ユーザ名でユーザ検索するメソッドは作成済みのため、作業不要。
APIテスト
- PostmanでログインAPIを叩いて、トークンを取得する。
- トークンをヘッダーについて、/article/list を叩て401にならないことを確認する。
トークンがない場合: 401になる。

トークンがある場合: 200 OKになる
Discussion