Graphql-authenticating-client
GraphQL-認証クライアント
認証は、ユーザーまたはプロセスのIDを検証するプロセスまたはアクションです。 アプリケーションがユーザーを認証し、匿名ユーザーがデータを使用できないようにすることが重要です。 このセクションでは、GraphQLクライアントを認証する方法を学びます。
Express JWT
この例では、jQueryを使用してクライアントアプリケーションを作成します。 リクエストを認証するには、サーバー側でon express-jwt モジュールを使用します。
「express-jwt」モジュールは、JWTトークンを使用してHTTP要求を認証できるミドルウェアです。 JSON Web Token(JWT)は、ログインしているユーザーを識別する長い文字列です。
ユーザーが正常にログインすると、サーバーはJWTトークンを生成します。 このトークンは、ログを明確に識別します。 言い換えれば、トークンはユーザーの身元の表現です。 そのため、次回、クライアントがサーバーにアクセスすると、必要なリソースを取得するためにこのトークンを提示する必要があります。 クライアントは、モバイルアプリケーションまたはWebアプリケーションのいずれかです。
図
この図を理解するために、段階的な手順に従います。
サーバーのセットアップ
以下は、サーバーをセットアップするための手順です-
ステップ1-プロジェクトに必要な依存関係をダウンロードしてインストールする
フォルダ auth-server-app を作成します。 端末からディレクトリを「 auth-server-app 」に変更します。 環境設定の章で説明されている手順3〜5に従います。
ステップ2-スキーマを作成する
プロジェクトフォルダma auth-server-app に schema.graphql ファイルを追加し、次のコードを追加します-
type Query
{
greetingWithAuth:String
}
ステップ3-リゾルバーを追加する
プロジェクトフォルダにファイル resolvers.js を作成し、次のコードを追加します-
リゾルバは、GraphQLのコンテキストオブジェクトで認証済みのユーザーオブジェクトが利用可能かどうかを確認します。 認証されたユーザーが利用できない場合、例外が発生します。
const db = require('./db')
const Query = {
greetingWithAuth:(root,args,context,info) => {
//check if the context.user is null
if (!context.user) {
throw new Error('Unauthorized');
}
return "Hello from finddevguides, welcome back : "+context.user.firstName;
}
}
module.exports = {Query}
ステップ4-Server.jsファイルを作成する
認証ミドルウェアは、JSON Web Tokenを使用して発信者を認証します。 認証用のURLは http://localhost:9000/login です。
これは後処理です。 ユーザーは、バックエンドから検証されるメールとパスワードを送信する必要があります。 有効なトークンが「jwt.sign」メソッドを使用して生成される場合、クライアントは後続のリクエストのためにヘッダーでこれを送信する必要があります。
トークンが有効な場合、「req.user」は、承認およびアクセス制御のために後のミドルウェアによって使用されるようにデコードされたJSONオブジェクトで設定されます。
次のコードは、リクエストを認証するために、jsonwebtokenとexpress-jwtの2つのモジュールを使用します-
- ユーザーが greet ボタンをクリックすると、/graphqlルートのリクエストが発行されます。 ユーザーが認証されていない場合、ユーザー自身の認証を求められます。
- ユーザーには、メールIDとパスワードを受け入れるフォームが表示されます。 この例では、/loginルートがユーザーの認証を担当します。 */loginルートは、ユーザーが提供した資格情報と一致するデータベースがあるかどうかを確認します。
- 資格情報が無効な場合、HTTP 401例外がユーザーに返されます。
- 資格情報が有効な場合、サーバーによってトークンが生成されます。 このトークンは、ユーザーへの応答の一部として送信されます。 これは、jwt.sign関数によって行われます。
const expressJwt = require('express-jwt');
const jwt = require('jsonwebtoken');
//private key
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
app.post('/login', (req, res) => {
const {email, password} = req.body;
//check database
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
//generate a token based on private key, token doesn't have an expiry
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
リクエストごとに、app.use()関数が呼び出されます。 これにより、expressJWTミドルウェアが呼び出されます。 このミドルウェアはJSON Web Tokenをデコードします。 トークンに保存されているユーザーIDが取得され、プロパティオブジェクトユーザーとしてリクエストオブジェクトに保存されます。
//decodes the JWT and stores in request object
app.use(expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
GraphQLコンテキスト内でユーザープロパティを使用できるようにするために、このプロパティは以下に示すように context オブジェクトに割り当てられます-
//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));
現在のフォルダパスに server.js を作成します。 完全なserver.jsファイルは次のとおりです-
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const expressJwt = require('express-jwt');//auth
const jwt = require('jsonwebtoken');//auth
const db = require('./db');
var port = process.env.PORT || 9000
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
const app = express();
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
app.use(cors(), bodyParser.json(), expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user && db.students.get(req.user.sub)}
})));
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
//authenticate students
app.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
app.listen(port, () => console.info(`Server started on port ${port}`));
ステップ5-アプリケーションを実行する
ターミナルでコマンド_npm_ startを実行します。 サーバーは9000ポートで稼働します。 ここでは、GraphiQLをクライアントとして使用して、アプリケーションをテストします。
ブラウザを開き、URL http://localhost:9000/graphiql を入力します。 エディタで次のクエリを入力します-
{
greetingWithAuth
}
以下の応答では、認証されたユーザーではないためエラーが発生しました。
{
"data": {
"greetingWithAuth": null
},
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"greetingWithAuth"
]
}
]
}
次のセクションでは、認証するクライアントアプリケーションを作成します。
JQueryクライアントのセットアップ
クライアントアプリケーションでは、スキーマ greetingWithAuth を呼び出す[あいさつ]ボタンが提供されます。 ログインせずにボタンをクリックすると、以下のエラーメッセージが表示されます-
データベースで利用可能なユーザーでログインすると、次の画面が表示されます-
あいさつ*にアクセスするには、まず以下のようにURL *http://localhost:9000/login routeにアクセスする必要があります。
応答には、サーバーから生成されたトークンが含まれます。
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus')
l("authenticated successfully")
.css({"color":"green",'font-weight':'bold'});
$("#greetingDiv")l('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
ログインに成功すると、以下に示すように_greetingWithAuth_スキーマにアクセスできます。 「bearer」トークンを使用した後続のすべてのリクエストには、「AuthorizationHeader」が必要です。
{
url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken}, type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}`
}
以下はindexlのコードです-
<!DOCTYPE html>
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
let loginToken = "";
$("#btnGreet").click(function() {
$.ajax({url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken},
type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}` }),
success: function(result) {
$("#greetingDiv")l("<h1>"+result.data.greetingWithAuth+"</h1>")
},
error:function(jQxhr,error) {
if(jQxhr.status == 401) {
$("#greetingDiv")l('please authenticate first!!')
.css({"color":"red",'font-weight':'bold'})
return;
}
$("#greetingDiv")l('error').css("color","red");
}
});
});
$('#btnAuthenticate').click(function() {
var email = $("#txtEmail").val();
var password = $("#txtPwd").val();
if(email && password) {
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus')
l("authenticated successfully")
.css({"color":"green",'font-weight':'bold'});
$("#greetingDiv")l('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
}else alert("email and pwd empty")
})
});
</script>
</head>
<body>
<h1> GraphQL Authentication </h1>
<hr/>
<section>
<button id = "btnGreet">Greet</button>
<br/> <br/>
<div id = "greetingDiv"></div>
</section>
<br/> <br/> <br/>
<hr/>
<section id = "LoginSection">
<header>
<h2>*Login first to access greeting </h2>
</header>
<input type = "text" value = "[email protected]" placeholder = "enter email" id = "txtEmail"/>
<br/>
<input type = "password" value = "pass123" placeholder = "enter password" id = "txtPwd"/>
<br/>
<input type = "button" id = "btnAuthenticate" value = "Login"/>
<p id = "authStatus"></p>
</section>
</body>
</html>