GraphQL - 身份认证

GraphQL - 身份认证 首页 / GraphQL入门教程 / GraphQL - 身份认证

身份验证是验证用户或进程身份的过程或动作。应用程序对用户进行身份验证以确保数据对匿名用户不可用是很重要的。在本节中,我们将学习如何对 GraphQL 客户端进行身份验证。

Express JWT

在此示例中,将使用jQuery创建客户端应用程序。为了验证请求,将在服务器端使用 express-jwt 模块。

express-jwt模块是一个中间件,可让您使用JWT令牌对HTTP请求进行身份验证。 JSON Web令牌(JWT)是一个长字符串,用于标识已登录的用户。

用户成功登录后,服务器将生成JWT令牌。该令牌明确标识日志。换句话说,令牌是用户身份的表示。因此,下一次,当客户端访问服务器时,它必须提供此令牌以获取所需的资源。客户端可以是移动应用程序或Web应用程序。

链接:https://www.learnfk.comhttps://www.learnfk.com/graphql/graphql-authenticating-client.html

来源:LearnFk无涯教程网

捷运 Module

设置服务器

以下是设置服务器的步骤-

步骤1  -  下载并安装依赖项

创建一个文件夹 auth-server-app 。从终端将目录更改为 auth-server-app 。请按照"环境设置"一章中介绍的步骤3至5进行操作。

步骤2  -  创建Schema文件

在项目文件夹 auth-server-app 中添加 schema.graphql 文件,并添加以下代码-

type Query
{
   greetingWithAuth:String
}

步骤3  -  添加解析器

在项目文件夹中创建文件 resolvers.js 并添加以下代码-

解析器将验证GraphQL的context对象中是否有经过身份验证的用户对象。如果未通过身份验证的用户,它将引发异常。

const db=require('./db')

const Query={
   greetingWithAuth:(root,args,context,info) => {

      //检查 context.user 是否为空
      if (!context.user) {
         throw new Error('Unauthorized');
      }
      return "Hello from LearnFk, welcome back : "+context.user.firstName;
   }
}

module.exports={Query}

步骤4  -  创建Server.js文件

身份验证中间件使用JSON Web令牌对调用者进行身份验证。身份验证的URL为 http://localhost:9000/login 。

如果令牌有效,则将使用解码的JSON对象设置请求用户,以供以后的中间件用于授权和访问控制。

以下代码使用两个模块-jsonwebtoken和express-jwt来验证请求

const expressJwt=require('express-jwt');
const jwt=require('jsonwebtoken');

//私钥
const jwtSecret=Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');

app.post('/login', (req, res) => {
   const {email, password}=req.body;
   
   //检查数据库
   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.use()函数。反过来,这将调用expressJWT中间件。该中间件将解码JSON Web令牌。存储在令牌中的用户ID将被检索并作为属性用户存储在请求对象中。

//解码 JWT 并存储在请求对象中
app.use(expressJwt({
   secret: jwtSecret,
   credentialsRequired: false
}));

为了使GraphQLcontext中的用户属性可用,该属性被分配给 context 对象,如下所示-

//使 req.user 可用于 GraphQL 上下文
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客户端

在客户端应用程序中,提供了一个greet按钮,它将调用架构 greetingWithAuth 。如果您单击按钮而不登录,它将显示以下错误消息:

Client Application Authentication

使用数据库中可用的用户登录后,将出现以下屏幕:

Client Application Authentication Successful

要访问问候,需要首先访问URL http://localhost:9000/login 路由,如下所示。

响应将包含从服务器生成的令牌。

$.ajax({
   url:"http://localhost:9000/login",
   contentType:"application/json",
   type:"POST",
   data:JSON.stringify({email,password}),
   success:function(response) {
      loginToken=response.token;
      $('#authStatus')
      .html("authenticated successfully")
      .css({"color":"green",'font-weight':'bold'});
      $("#greetingDiv").html('').css({'color':''});
   },
   error:(xhr,err) =>  alert('error')
})

成功登录后,无涯教程可以访问如下所示的 greetingWithAuth 模式。所有随后的带有承载令牌的请求都应该有一个Authorizationheader。

{ 
   url: "http://localhost:9000/graphql",
   contentType: "application/json",
   headers: {"Authorization": 'bearer '+loginToken},  type:'POST',
   data: JSON.stringify({
   query:`{greetingWithAuth}`
}

以下是index.html的代码-

无涯教程网

<!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").html("<h1>"+result.data.greetingWithAuth+"</h1>")
                  },
                  error:function(jQxhr,error) {
                     if(jQxhr.status == 401) {
                        $("#greetingDiv").html('please authenticate first!!')
                        .css({"color":"red",'font-weight':'bold'})
                        return;
                     }
                     $("#greetingDiv").html('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')
                        .html("authenticated successfully")
                        .css({"color":"green",'font-weight':'bold'});
                        $("#greetingDiv").html('').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="mohtashim.mohammad@tutorialpoint.org" 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>

祝学习愉快!(内容编辑有误?请选中要编辑内容 -> 右键 -> 修改 -> 提交!)

技术教程推荐

如何做好一场技术演讲 -〔极客时间〕

ZooKeeper实战与源码剖析 -〔么敬国〕

Linux内核技术实战课 -〔邵亚方〕

MySQL 必知必会 -〔朱晓峰〕

技术面试官识人手册 -〔熊燚(四火)〕

编程高手必学的内存知识 -〔海纳〕

JavaScript进阶实战课 -〔石川〕

超级访谈:对话毕玄 -〔毕玄〕

工程师个人发展指南 -〔李云〕

好记忆不如烂笔头。留下您的足迹吧 :)