Spring Security | JWT認証 – JavaScriptからログインを実行する
2022.08.18トークンを取得することができたので、次はフロントからログインを試みます。今回はフォームを用意せずに直接パラメータを記載してしまいます。
前回の記事
JavaScriptでログインする
以下のような単純な作りでログインをしてみます
このPOSTというのはログインが必須な処理です。前に作成したバージョンでは、最初にGETボタンでCSRFトークンを設定すれば実行ができていましたが、今は認証が必要なのでログインしないと利用できなくなっています。
以下がJavaScriptのコードになります。htmlなどは適当に書いてます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="get">GET</button>
<button id="post">POST</button>
<button id="login">LOGIN</button>
<hr>
<script>
const getBtn = document.getElementById("get");
getBtn.addEventListener('click',doget);
const postBtn = document.getElementById("post");
postBtn.addEventListener('click',dopost);
// ログインボタン
const loginBtn = document.getElementById("login");
loginBtn.addEventListener('click',dologin);
// ログイン処理
function dologin(){
const csrfToken = document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/, '$1');
fetch('http://localhost:8080/api/login',{
method:'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN' : csrfToken
},
body : JSON.stringify({
'username' : 'misaka',
'password': 'mikoto'
})
})
.then(res => res.text())
.then(str => console.log(str))
}
function doget(){
fetch('http://localhost:8080/get',
{
method:'GET',
credentials: 'include'
})
.then(res => res.text())
.then(str => console.log(str))
}
function dopost(){
const csrfToken = document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/, '$1');
console.log(csrfToken);
fetch('http://localhost:8080/post',{
method:'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN' : csrfToken
},
})
.then(res => res.text())
.then(str => console.log(str))
}
</script>
</body>
</html>
- パラメータのbodyにJSON.stringifyを利用してusernameとpasswordを設定しています
まずGET→POSTとした例です
csrfトークンは取得できていますが、認証してないのでエラーになっています。
次にGET→LOGIN→POSTとした例です
ログインができているのでPOSTの処理が行えています。
ログイン判定
ところでログイン判定はどうなっているのでしょうか?
実はログインすると以下の「JSESSIONID」というクッキーが登録されていることがわかります
これを見てログイン済ユーザーとしているようです
コントローラーで認証情報を出力してみます
@GetMapping("/get")
public String getSample(){
System.out.println("GET");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
System.out.println(authentication);
return "sample GET is done";
}
@PostMapping("/post")
public String postSample(){
System.out.println("POST");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
System.out.println(authentication);
return "sample POST is done";
}
GET→LOGIN→POSTの順番で行いPOSTの段階で認証情報が取得できることを確認します。
GET
AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
POST
UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=misaka, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]], Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_USER]]
ログイン後は認証情報が取得できていることがわかります。
次にCookieからJSESSIONIDを削除してPOST送信をしてみます
認証で弾かれています。ログインできていればGETでも認証情報が取得できるのですが、認証情報は消されています
GET
AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
もう一度ログインしてみます
CookieにJSESSIONIDが追加されています。この状態でGETしてみます
GET
UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=misaka, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]], Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_USER]]
認証情報が取得できています。
このようにログインを実施することでJSESSIONIDが設定されて、ログイン判定を行っていることがわかりました。
しかし、これでは正しいJWTトークンである保証ができないと思います。次回はJWTトークンの検証を行います。