react+apollo+prisma入门demo搭建---5、身份验证

react+apollo+prisma入门demo搭建—5、身份验证

根据HOW TO GRAPHQL官网的例子,做了些对最新版的改动,适合最新框架的学习。

本系列文章注重前端方面的开发,对于node方面的放在下一个系列。在此过程中有任何问题,都欢迎在评论中提问,会及时反馈

系列目录:

第一章. Frontend开始
第二章. Queries组件编写(Loading Links)
第三章. Mutations组件编写(Creating Links)
第四章. 页面路由
第五章. 身份验证

为了照顾更加全面的读者,我写的会尽量详细,熟练的开发者可进行快速选择性的阅读

页面路由

本节我们来学习如何使用Apollo实现身份验证功能,以便为用户提供注册和登录功能。

准备Login组件

在components文件夹中创建Login.js文件

import React, { Component } from 'react'
import { AUTH_TOKEN } from '../constants'

class Login extends Component {
  state = {
    login: true, // switch between Login and SignUp
    email: '',
    password: '',
    name: '',
  }

  render() {
    const { login, email, password, name } = this.state
    return (
      

{login ? 'Login' : 'Sign Up'}

{!login && ( this.setState({ name: e.target.value })} type="text" placeholder="Your name" /> )} this.setState({ email: e.target.value })} type="text" placeholder="Your email address" /> this.setState({ password: e.target.value })} type="password" placeholder="Choose a safe password" />
this._confirm()}> {login ? 'login' : 'create account'}
this.setState({ login: !login })} > {login ? 'need to create an account?' : 'already have an account?'}
) } _confirm = async () => { // 接下来需要完成的 } _saveUserData = token => { localStorage.setItem(AUTH_TOKEN, token) } } export default Login

该组件通过this.state.login状态来实现登录和注册页面的切换,但状态为true时,页面展示只有两个输入框的登录页面,当状态变为false时,展现三个输入框的注册页面。

_confirm 函数将用于实现我们需要为登录功能发送的变更请求。
接下来,我们还需要一个constants.js文件,我们用它来定义我们存储在浏览器的localStorage中的凭据的key。

在src目录下新建constants.js文件

export const AUTH_TOKEN = 'auth-token'

然后我们将新的Login组件加入到我们的路由当中,打开App.js


         
         
         

并引入Login组件

import Login from './Login'

最后,我们再Header组件中加上可以跳转至Login的导航

render() {
  const authToken = localStorage.getItem(AUTH_TOKEN)
  return (
    
Hacker News
new {authToken && (
|
submit
)}
{authToken ? (
{ localStorage.removeItem(AUTH_TOKEN) this.props.history.push(`/`) }} > logout
) : ( login )}
) }

在Header的右侧,我们加入了前往Login组件的导航,并且我们会先判断用户登录与否,没登录的话不提供create页面的导航

别忘了要在Header中引入需要的依赖

import { AUTH_TOKEN } from '../constants'

使用有身份验证的变更

注册和登录是两个常规的GraphQL变更,我们可以像使用之前的createLink变更一样使用它。
打开Login.js,在前面添加两个变更定义

const SIGNUP_MUTATION = gql`
  mutation SignupMutation($email: String!, $password: String!, $name: String!) {
    signup(email: $email, password: $password, name: $name) {
      token
    }
  }
`

const LOGIN_MUTATION = gql`
  mutation LoginMutation($email: String!, $password: String!) {
    login(email: $email, password: $password) {
      token
    }
  }
`

同时在className为flex mt3的div中添加以下代码

this._confirm(data)} > {mutation => (
{login ? 'login' : 'create account'}
)}
this.setState({ login: !login })} > {login ? 'need to create an account?' : 'already have an account?'}

并添加所需依赖

import { Mutation } from 'react-apollo'
import gql from 'graphql-tag'

现在我们终于要开始实现_confirm函数了

_confirm = async data => {
  const { token } = this.state.login ? data.login : data.signup
  this._saveUserData(token)
  this.props.history.push(`/`)
}

这样我们就已经基本实现了一个带有身份功能的Login组件了,接下来就是Apollo如何配合的事情了

使用身份验证token配置Apollo

既然我们已经可以拿到token了,那么我们就需要把token添加进我们的每一个请求中。
Apollo提供了一种很好的方法,通过使用中间件的概念来验证所有请求,实现为Apollo Link。
让我们来添加该依赖

yarn add apollo-link-context

然后我们需要改造我们的index.js,在创建httpLink和ApolloClient实例之间放置以下代码:

const authLink = setContext((_, { headers }) => {
  const token = localStorage.getItem(AUTH_TOKEN)
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : ''
    }
  }
})

并且引入依赖

import { setContext } from 'apollo-link-context'
import { AUTH_TOKEN } from './constants'

每次ApolloClient向服务器发送请求时,都会调用此中间件。

Note: 如果你想了解更多关于Apollo关于身份验证方面的信息,点击这里

接下来我们要确保link被正确配置进apollo client

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
})

现在如果token存在的话,我们所发送的所有请求都会通过身份验证了

在服务端启用身份验证

我们需要确保只有通过身份验证的用户才能发布新链接,所以需要在服务端做一点小更改
打开/server/src/resolvers/Mutation.js,找到post函数,修改为以下

function post(parent, args, context) {
  const userId = getUserId(context)
  return context.prisma.createLink({
    url: args.url,
    description: args.description,
    postedBy: { connect: { id: userId } },
  })
}

我们从请求的Authorization header中提取userId,并作为link的一个postedBy属性传出。

现在让我们重启两个服务,然后注册登录账户,发送一个create请求试试吧,目前发送create请求回到LinkList页面时并不会展示你刚才添加的那一条,需要手动刷新,这个我们之后会解决这个问题。

本节我们成功实现了页面的身份验证配置!马上开始下一步的旅程吧。

本章项目github 分支地址

https://github.com/zust-hh/simple-hackernews/tree/Frontend-topic5

你可能感兴趣的:(graphql,react,Apollo,GrapgQL,prisma,react)