[Node.js] Auth 체크

권규리·2024년 3월 6일

🧱Node.js

목록 보기
12/15

페이지 중에서 아무나 접근할 수 있는 페이지 또는 관리자만 접근할 수 있는 페이지, 로그인한 사람만 접근할 수 있는 페이지, 로그인을 했는데 또다시 로그인 페이지로 진입하는 등 페이지에 대한 권한이 각각 다르기 때문에 Auth를 확인해야 한다.

그러려면 HOC를 사용 !!

const EnhancedComponent = higherOrderComponent(WrappedComponent);

👩🏻‍💻 HOC는 함수형태이며, 다른 컴포넌트(WrappedComponent)를 받은 후에 새로운 컴포넌트(EnhancedComponent)를 반환하는 함수이다.

⭐ 동작 과정

1. HOC에서 BE로 req를 날린다.

2. 현재 페이지에 들어와있는 유저의 상태정보를 가져온다.

ex) 상태정보: 로그인이 되어있는 사람인지, 관리자인지 등등

3. 유저의 상태정보를 보고 페이지에 대한 권한이 있는지 판단한다.


(1) Server

⭐ Index.js

app.get('/api/users/auth', auth ,(req,res)=>{
    //여기까지 통과해 왔다는 의미는 Auth가 true라는 것
  
    res.status(200).json({
        _id: req.user._id,
        isAdmin: req.user.role === 0 ? false : true,
        isAuth:true,
        email: req.user.email,
        name: req.user.name,
        lastname: req.user.lastname,
        role: req.user.role,
        image: req.user.image
    })
})

⭐ middleware > auth.js

const { User }= require("../models/User")

let auth = (req, res, next)=> {

    // client 쿠키에서 토큰을 가져온다.
    let token= req.cookies.x_auth;
  
    User.findByToken(token, (err,user)=>{
        if(err) throw err;
        if(!user) return res.json({ isAuth: false, error: true})
        req.token= token;
        req.user= user;
        next();
    })
}

module.exports = { auth };

⭐ models > User.js

userSchema.statics.findByToken= function(token, cb){
    var user= this;

    jwt.verify(token,'secretToken', function(err, decoded){
        //  token을 디코드 해서 userId를 사용하여 DB에서 유저를 찾은 후,
        // 쿠키에서 가져온 token과 DB에 보관된 token이 일치하는지 확인
        user.findOne({"_id": decoded, "token": token})
        .then((user)=>{
            cb(null, user);
        })
        .catch((err)=>{
            return cb(err);
        })
    })
}

👩🏻‍💻위의 세개의 컴포넌트를 해석하자면 !!

  • middleware > Auth.js에서 cookie에 저장된 token을 가져와서 models > User.js에서 복호화
  • token을 복호화 하면 userId가 나옴
  • userId를 이용해서 DB의 userCollection에서 유저를 찾은 후, 쿠키에서 가져온 token이 유저도 가지고 있는지 확인
  • 이때 없으면 Auth False, 쿠키가 일치하면 Auth True가 됨

📢 HOC이 유저에게 어떤 권한이 있는지 확인하기 위해, server > index.js > auth router로 req를 보낸다.


(2) Client

⭐HOC > auth.js

import React, { useEffect } from 'react'
import { useDispatch } from 'react-redux'
import { useNavigate } from 'react-router-dom';
import { auth } from '../_actions/user_action';

export default function(SpecificComponent, option, adminRoute = null) {
    function AuthenticationCheck(){
        const dispatch= useDispatch();
        const navigate= useNavigate();

        useEffect(()=>{
            dispatch(auth())
            .then(response =>{
                console.log(response);

                // 분기처리
                // 로그인 하지 않은 상태
                if(!response.payload.isAuth){
                    if(option){
                        // 로그인 안한 사람이 로그인 한 사람만 접근 가능한 페이지에 들어갈 때
                        navigate('/login');
                    }
                }else{
                    // 로그인 한 상태
                    // 관리자가 아닌데 관리자 페이지에 들어가려는 경우
                    if(adminRoute && !response.payload.isAdmin){
                        navigate('/');
                    }else{
                        // 로그인 한 사람이 로그인페이지나 회원가입 페이지에 접근할 때
                        if(option===false){
                            navigate('/')
                        }
                    }
                }
            })
        },[])

        return(
            <SpecificComponent/>
        )
    }
    return AuthenticationCheck
}

여기서 SpecificComponent, option, adminRoute = null 세개의 파라미터가 존재한다.

  • SpecificComponent는 HOC 컴포넌트 안에 넣을 컴포넌트를 뜻한다.

  • option은 누가 접근 가능한지를 나타낸다.
    null : 누구든 접근 가능, true: 로그인한 사람만 접근 가능, false: 로그인한 사람은 접근 불가능

  • adminRoute는 관리자만 접근 가능함을 나타내며, true : 관리자만 접근 가능이지만 현재는 누구나 접근 가능한 null로 설정해두었다.

⭐ route.js

import React from 'react'
import { HashRouter as Router, Route, Routes } from 'react-router-dom';
import LandingPage from './components/views/LandingPage/LandingPage';
import LoginPage from './components/views/LoginPage/LoginPage';
import RegisterPage from './components/views/RegisterPage/RegisterPage';
import Auth from './hoc/auth';

export default function route() {
    const AuthLandingPage = Auth(LandingPage, null);
    const AuthLoginPage = Auth(LoginPage, false);
    const AuthRegisterPage = Auth(RegisterPage, false);

    return (
        <>
            <Router>
                <Routes>
                    <Route path="/" element={ <AuthLandingPage /> } />
                    <Route path="/login" element={ <AuthLoginPage /> }/>
                    <Route path="/register" element={ <AuthRegisterPage /> } />
                </Routes>
            </Router>
        </>
    )
}

HOC은 컴포넌트들이 모두 모여있는 route.js에서 설정해주었다.
Auth 안에 있는 LandingPage, LoginPage, RegisterPage가 위에서 말한 SpecificComponent 파라미터이다. 또한, null과 false option 파라미터이다.


⭐ user_actions.js

export async function auth(){
    // get method는 body부분이 필요 없음
    const request= await axios.get('/api/users/auth')
    .then(response=> response.data)

    return{
        type: AUTH_USER,
        payload: request,
    }
}

⭐ user_reducer.js

case AUTH_USER:
  return{...state, userData: action.payload}
break;

userData: action.payload에서 userData는 작명한 것, action.payload는 server > index.js의 auth router에 있는 유저의 정보 (isAuth, isAdmin, email 등)가 모두 담겨있다.

때문에, 로그인할 때 console을 확인해보면 server의 auth route에 있는 것들이 모두 나타난다.


위처럼 HOC 컴포넌트를 생성해주고 적용시키니까, 로그인을 한 사람은 Login, Register 페이지에 접근할 수 없도록 설정할 수 있었다.

profile
기록장 📝

0개의 댓글