他叫钊哥 發表於 2023-2-19 14:48:00

GraphQL(三) - Authentication 和 Authorication

<p>本文介绍GraphQL中的Authenication和Authorication</p>
<p>参考:</p>
<ul>
<li>https://graphql.org/learn/authorization/</li>
<li>https://www.apollographql.com/docs/apollo-server/security/authentication/</li>
</ul>
<h3 id="authenication和authorication的区别">Authenication和Authorication的区别</h3>
<p>Authenication 和 Authorication 的概念十分容易混淆,两者的定义如下:</p>
<ul>
<li>Authenication 指用户认证,即是否有用户登录,哪个用户登录</li>
<li>Authorication 指用户权限认证,再具体的操作中决定用户是否有权利使用查看数据或调用方法</li>
</ul>
<h3 id="authenication">Authenication</h3>
<p>提供用户的authenication有多种方式,包括HTTP header和JSON web token。<br>
下面给出一个创建Authenication的示例</p>
<h5 id="创建用户组的schema">创建用户组的schema</h5>
<p>分别创建一个用户信息的type,并定义创建用户和登录的方法</p>
<pre><code class="language-gql">type AuthPayload {
        token: String!
        name: String!
}

input UserCreateInput {
        name: String!
        password: String!
}

type Mutation {
        createUser(data: UserCreateInput): String
        login(data: UserCreateInput): AuthPayload
        logout(data: UserCreateInput, param: Int!): Int
}
</code></pre>
<h5 id="定义本地createuser和login的resolver">定义本地CreateUser和Login的Resolver</h5>
<p>通常情况下,用户在用前端创建用户时,会传入用户名和密码,后端不会直接保存用户密码,而是将用户信息加密为webtoken储存起来,而login的情况下,也是会将用户用户名和密码的信息与weebtoken进行比对。<br>
可以在context中,设置一个用户组缓存来储存数据,同样适用于将用户信息储存于数据库或云端。</p>
<pre><code class="language-ts">const resolver = {
        Mutation: {
                createUser: async (parent: any, args: any, ctx: any, info: any) =&gt; {
                  if (args.data.password.length &lt; 8) {
                        throw new Error('Password must be 8 characters or longer.')
                  }
                  const password = await bcrypt.hash(args.data.password, 10);
                  const id = uuidv4();
                  const token = jwt.sign({ userId: id }, 'password');
                  ctx.users.push({
                        id,
                        name: args.data.name,
                        password,
                        token
                  });
                  return token;
                },
                login: async (parent: any, args: any, ctx: any, info: any) =&gt; {
                  const user = ctx.users.find(u =&gt; u.name === args.data.name);
                  if (!user) throw Error('User not exist');
                  const isMatch = await bcrypt.compare(args.data.password, user.password);
                  if (!isMatch) throw new Error('Password mismatch');
                  return {
                        name: user.name,
                        token: user.token ? user.token : jwt.sign({ userId: user.id }, 'password'),
                  }
                },
        }
}
</code></pre>
<h3 id="authorization">Authorization</h3>
<p>用上述步骤执行完Authentication的操作以后,需要验证用户操作函数是否有权限只需要在相应方法的Resolver中进行验证即可,调用Query或Mutation可以在Header中添加一个由后端返回给前端的token,示例如下:</p>
<p>后端:</p>
<pre><code class="language-ts">const getUserId = (request) =&gt; {
const token = request.headers.authorization;
if (!token) {
    throw new Error('Authentication required')
}
const decoded = jwt.verify(token, 'password')
return decoded.userId
}

const resolver = {
        Mutation: {
                callFunction: async (parent: any, args: any, ctx: any, info: any) =&gt; {
                        const id = getUserId(ctx.request);
                        if (!id) throw Error('ID not exist');
                        // Do operation
                }
        }
}
</code></pre>
<p>在Apollo GraphQL中可以在前端的header加一个authorication的字段,输入token:</p>
<p><img src="https://img2023.cnblogs.com/blog/1507862/202302/1507862-20230219143955787-1772709737.png"></p>
<p>前端可以在创建Apollo GraohQL Module时,创建一个MidWare包含我们的header:</p>
<pre><code class="language-ts">const authMiddleware = new ApolloLink((operation: any, forward: any) =&gt; {
operation.setContext({
    headers: new HttpHeaders().set(
      "Authorization",
      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."        //Token
    ),
});
return forward(operation);
});

export function createApollo(httpLink: HttpLink): ApolloClientOptions&lt;any&gt; {
return {
    link: httpLink.create({uri}),
    cache: new InMemoryCache(),
};
}
export function createApolloWithAuth(httpLink: HttpLink): ApolloClientOptions&lt;any&gt; {
return {
    link:from([
      authMiddleware,
      httpLink.create({
      uri,
      }),
    ]),
    cache: new InMemoryCache(),
};
}
</code></pre><br><br>
来源:https://www.cnblogs.com/Asp1rant/p/17134703.html
頁: [1]
查看完整版本: GraphQL(三) - Authentication 和 Authorication