Apollo ve React Kullanarak Fullstack Kullanıcı Kimlik Doğrulama Sistemi - Login/Register

Uğur Emirmustafaoğlu

Uğur Emirmustafaoğlu /

5 dakika ⏲––– okuma

#React#Apollo-Server#Apollo-Client#GraphQL#JWT#Postgres#Chakra-UI

Kimlik doğrulama sistemleri, kullanıcının temel bilgilerinin(email, şifre vb.) alınarak bir veritabanında şifrelenerek saklandığı ve kullanıcı uygulamaya giriş yaparken kullanıcıdan alınan bilgilerin veritabanındakilerle uyuşup uyuşmadığının kontrol edildiği sistemlerdir. Aslında hepimizin aşina olduğu giriş yap/kaydol işleminin arkasındaki sistemden bahsediyorum. Bu uygulamada server ve client'ın GraphQL üzerinden haberleştiği bir fullstack kimlik doğrulama sistemi geliştirdim. Bu projeyi hazırlarken aşağıdaki teknolojilerden yararlandım:

1. Kullandığım Araçlar ve Tercih Sebeplerim

apollo-server-express

GraphQL ile server oluştururken en güçlü seçenekler arasında apollo-server ve apollo-server-express yer alıyor. Apollo'nun kendi sitesinde verdiği bilgilere göre apollo-server'ın arka planında da apollo-server-express çalışıyor fakat ince ayarlamalar için apollo-server-express tavsiye ediliyor. Bu proje bir boilerplate olduğunda geliştirmelere ve detaylı konfigürasyon değişikliklerine açık olmasını istedim ve bu nedenle apollo-server-express'i server olarak tercih ettim.

jwt

Daha öncesinde buna benzer bir projede session'lar ile çalışmıştım. Bu sefer farklı bir deneyim olması için JWT tercih ettim. Cookie olarak gönderdiğim refresh-token ve access-token'larımı jwt ile imzalayarak gönderdim ve kullanıcıdan gelen request'leri de bir adet middleware yardımı ile authenticated olup olmamasına göre değerlendirdim.

typeorm ve typegraphql

Bu iki kütüphanenin birlikte ne denli uyumlu çalıştıklarını Ben Awad'ın şu videosunda gördüğümden beri vazgeçilmez araçlarım arasında yer alıyorlar. Typeorm Typescript desteği olan bir ORM, yani veritabanı etkileşim aracı. Onun sayesinde postgres veritabanım ile iletişimimi saf SQL sorguları yazmak yerine daha zarif bir biçimde utility fonksiyonları ile yazıyorum.

typegraphql ise Typeorm ile yazmış olduğumuz entity dosyalarına birer @Field decorator'ı ekleyerek ayrıca type definitionları yazmadan kolayca Graphql type'larımı hazırlamış oluyorum. Bu iki aracı detaylıca öğrenmek isterseniz Ben Awad'ı muhakkak izleyin derim.

import { Field, Int, ObjectType } from 'type-graphql';
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from 'typeorm';

@ObjectType()
@Entity('users')
export class User extends BaseEntity {
  @Field(() => Int)
  @PrimaryGeneratedColumn()
  id!: number;

  @Field(() => String)
  @Column('text', { unique: true })
  email!: string;

  @Field(() => String)
  @Column('text', { unique: true })
  username!: string;

 @Column('text')
  password!: string;

  @Column('int', { default: 0 })
  tokenVersion: number;
}

ioredis

Redis bu projede bana rate-limiting yaparken yardımcı oldu. DDOS ataklarını önlemek adına kullanıcı ip adresleri ile Redis'te keyler sakladım. Böylece anlık ciddi bir talep olduğunda ilgili ip adresini belirli bir süre engelleme şansım oldu. Redis'in ne kadar hızlı ve bu tarz işler için ne kadar elverişli olduğunu sizler zaten biliyorsunuz.

apollo-client

Browser tarafında React ile kullanıcı arayüzünü oluşturdum. Apollo-client ile uygulamamı sardım ve server tarafındaki verileri GraphQL sorguları ile kolayca çağırabildim.

const client = new ApolloClient({
  link: from([tokenRefreshLink, authLink, httpLink]),
  cache: new InMemoryCache({}),
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root')
);

graphql-code-generator

Bu aracın ne kadar işe yaradığını ve vakit kazandırdığını anlatmak mümkün değil. Bilgisayarınıza kuracağınız bir CLI yardımı ile sizlere GraphQL sorgularınıza göre custom React hook yapıları oluşturuyor, hem de tamamen Typescript destekli. Bunun sayesinde artık apollo-client'ın sunduğu useQuery ve useMutation nasıl çalışıyordu onu dahi unuttum. 🥳

formik

Bu vesile ile form oluşturma çilesini sırtımızdan alan formik ve react-hook-form kütüphanelerine ve geliştiricilerine tekrar teşekkürlerimi iletiyorum. Bunlar birer harika. Bu projedeki tercihim ise formik'ten yana oldu. Geçerli bir sebebi yok sanırım. Yoksa ikisi de harika kütüphaneler. Şuraya da oluşturmuş olduğum custom input field'ı bırakayım da tam olsun.

import { FormControl, FormErrorMessage, FormLabel, Input, Textarea } from '@chakra-ui/react';
import { useField } from 'formik';
import React, { FC, InputHTMLAttributes } from 'react';

type IProps = InputHTMLAttributes<HTMLInputElement | HTMLTextAreaElement> & {
  name: string,
  label: string,
  textarea?: boolean,
};

const InputField: FC<IProps> = ({ label, textarea, size: _, ...props }) => {
  const [field, { error }] = useField(props);
  return (
    <FormControl isInvalid={!!error}>
      <FormLabel htmlFor={field.name}>{label}</FormLabel>
      {!textarea ? (
        <Input {...field} {...props} id={field.name} placeholder={props.placeholder} />
      ) : (
        <Textarea {...field} {...props} id={field.name} placeholder={props.placeholder} />
      )}
      {error ? <FormErrorMessage>{error}</FormErrorMessage> : null}
    </FormControl>
  );
};

export default InputField;

chakra-ui

Sürekli Material-UI kullanmaktan gına geldiği için bu projede Chakra-UI tercih ettim. Gayet eğlenceli bir kütüphane olduğunu söyleyebilirim. Tailwind seven arkadaşlar bunu da seveceklerdir.

2. Sonraki Adımlar ve Eklenecek Özellikler

Projenin şu an için geliştirme aşamasında olduğunu söyleyebilirim. Özellikle TypeORM tarafında keşfedilecek birçok özellik var. Hele benim gibi frontend tarafınıza daha çok güveniyor ve backend'e yeni yeni ısınıyorsanız TypeORM'u keşfetmenin heyecanlı bir süreç olduğunu söylemek isterim. Şimdilik kafamda eklemeyi düşündüğüm özellikler ve yapılacaklar listesine şunları sıralayabiliriz:

  • Global error handler: TypeORM hataları yakalayacak global bir fonksiyon yazma imkanı tanıyor sanırım. Yakında bunu keşfetmeyi planlıyorum ki her resolver için ayrı ayrı error-handling yapmayalım.
  • Şifre yenileme - forgot password: Şimdilik şifrenizi unuttunuz mu yandınız ama yakında şifremi unuttum özelliği geliyor. ⏳

3. Sonuç

Bu proje ile JWT kullanarak GraphQL authentication server nasıl kurulur onu öğrendim. Buna ek olarak React tarafında cookie yönetimi ve HTTP headers konusunda yeni deneyimler edindim. Bir de Vercel'de environment variable'ların REACT_APP_ prefixi ile yazılması gerektiğini yoksa saatlerce boşa vakit harcanabileceğini görmüş oldum. İşte bunlar hep tecrübe.

Sonraki projelerde görüşmek üzere. 🤗

0
0
0
0
0