๋ณธ๋‚ด์šฉ์€ ํ•„์ž์˜ " React&Python์œผ๋กœ ์›น๊ฐœ๋ฐœ(๋งํฌ์„œ๋น„์Šค)" ์นดํ…Œ๊ณ ๋ฆฌ ๊ฐœ๋ฐœ์†Œ์Šค์— ๊ณ„์† ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

( ์†Œ์Šค ํด๋”๋Š” ์œ„ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ž˜ ์ฝ์–ด๋ณด๊ณ ,  git ์†Œ์Šค๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. )

 

react-keycloak ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ useKeycloak Hook๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ˜ธ์ถœ

 

react-keycloak ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ useKeycloak Hook๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ˜ธ์ถœ

๋ณธ๋‚ด์šฉ์€ ํ•„์ž์˜ " React&Python์œผ๋กœ ์›น๊ฐœ๋ฐœ(๋งํฌ์„œ๋น„์Šค)" ์นดํ…Œ๊ณ ๋ฆฌ ๊ฐœ๋ฐœ์†Œ์Šค์— ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ( ์†Œ์Šค ํด๋”๋Š” ์œ„ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ž˜ ์ฝ์–ด๋ณด๊ณ , git ์†Œ์Šค๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ) ์ง€๋‚œํŽธ

firstvalue.tistory.com

 

์ด์ „๊ธ€์—์„œ Keycloak ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋กœ๊ทธ์ธ์„ ํ•˜๋„๋ก ์ฒ˜๋ฆฌํ–ˆ์—ˆ๋‹ค.

 

์ด๋ฒˆ์—๋Š” Keycloak ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธํ›„ token ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€ Keycloak์˜ ์ €์žฅ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํ™•์ธ ํ•ด๋ณด์ž. 

 

์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„œ ์‹ ๊ทœ ์†Œ์Šค๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

์‹ ๊ทœ 1๊ฐœ์™€ ๊ธฐ์กด ์†Œ์Šค๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  react์— ์‹ ๊ทœ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•  ์˜ˆ์ •์ด๋‹ค.

1. userinfo.jsx (์‹ ๊ทœ)

2. menu.jsx (์ˆ˜์ •)

3. ์‹ ๊ทœ ํŒจํ‚ค์ง€ ์„ค์น˜ :  yarn add base-64

 

๋จผ์ € JWT ์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํžˆ ์„ค๋ช…ํ•˜์ž.
๋กœ๊ทธ์ธ์‹œ ํ† ํฐ ๊ด€๋ จ๋œ ์ธ์ฆ์„  ๋Œ€๋ถ€๋ถ„ ์‚ฌ์šฉํ•œ๋‹ค.
๊ทธ ์ค‘์—์„œ๋„ JWT๋Š” ์›น ํ‘œ์ค€์„ ๋”ฐ๋ฅด๊ณ  ์žˆ์œผ๋ฉฐ, JSON ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
JWT์˜ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋กœ, ์›น ํ‘œ์ค€์„ ๋”ฐ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๋ถ€๋ถ„์˜ ์–ธ์–ด๊ฐ€ ์ด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

JWT๋Š” ๊ฐ๊ฐ์˜ ๊ตฌ์„ฑ์š”์†Œ๊ฐ€ ์ (.) ์œผ๋กœ ๊ตฌ๋ถ„์ด ๋˜์–ด ์žˆ์œผ๋ฉฐ , ๊ตฌ์„ฑ์š”์†Œ๋Š” HEADER(ํ—ค๋”).PAYLOAD(๋‚ด์šฉ).SIGNATURE(์„œ๋ช…) ํ˜•ํƒœ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.  

 

JWT ๋””์ฝ”๋”ฉ ํ™•์ธ ์‚ฌ์ดํŠธ : jwt.io

 

์•„๋ž˜ ์†Œ์Šค์—์„œ๋Š” ์ถ”๊ฐ€์ ์œผ๋กœ PAYLOAD ๋””์ฝ”๋”ฉ๊นŒ์ง€ ํฌํ•จํ•œ๋‹ค.

โŒ˜ userinfo.jsx ( ์œ„์น˜: linkservice/client/src/component/userinfo.jsx )

---------------------------------------------------------------------------------------------------

์•„๋ž˜ ์†Œ์Šค๋ฅผ ๋ฐ˜์˜ํ•œ๋‹ค.

import { useKeycloak } from "@react-keycloak/web";
import base64 from "base-64";
import React from "react";

const UserInfo = () => {

    const { keycloak } = useKeycloak();
    let payload, decodingInfo;
    
    const accessToken = keycloak.idToken;

    if (accessToken) {
      payload = accessToken.split('.')[1];
      decodingInfo = base64.decode(payload);
    }

  return (
    <div className="container">
      <div >

        <p>idToken ์ •๋ณด</p>
        <textarea cols="100" rows="8" value={keycloak.idToken} readOnly>
        </textarea>

        <p>token ์ •๋ณด</p>
        <textarea cols="100" rows="8" value={keycloak.token} readOnly>
        </textarea>

        <p>payload ์ •๋ณด</p>
        <textarea cols="100" rows="8" value={decodingInfo} readOnly>
        </textarea>

      </div>    
    </div>    
   )
}
export default UserInfo

 

๊ฐ„๋‹จํžˆ ์„ค๋ช…ํ•˜๋‹ค๋ฉด,

useKeycloak Hook๋ฅผ ํ†ตํ•ด keycloak ๊ฐœ๋ณ„ ๋ณ€์ˆ˜์— ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ํ• ๋‹นํ•˜๊ณ , accessToken๊ฐ’์„ ๋ฐ›์•„์˜จ๋‹ค.

import { useKeycloak } from "@react-keycloak/web";
//....
//....
//....
      const { keycloak } = useKeycloak();
      
// keycloak๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธ์ด ๋˜์—ˆ์„ ๊ฒฝ์šฐ ํ† ํฐ๊ฐ’์„ ๋ฐ›๊ฒŒ ๋œ๋‹ค.
//.....
      const accessToken = keycloak.idToken;

 

accessToken๊ฐ’์ด ์žˆ์„ ๊ฒฝ์šฐ, ์ฆ‰ ์ •์ƒ ๋กœ๊ทธ์ธ์ด ๋˜์—ˆ์„๋•Œ, JWT๊ตฌ์กฐ์ƒ splitํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด PAYLOAD๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ

base64๋กœ ๋‹ค์‹œ decode๋ฅผ ํ•œ๋‹ค. 

    if (accessToken) {
      payload = accessToken.split('.')[1];
      decodingInfo = base64.decode(payload);
    }

 

 

โŒ˜ menu.jsx ( ์œ„์น˜: linkservice/client/src/component/menu.js )

---------------------------------------------------------------------------------------------------

์ด์ „ menu.jsx ์†Œ์Šค๋ฅผ ์ž„์‹œ๋กœ ์ˆ˜์ •ํ•˜์—ฌ ์ •๋ณด๋ฅผ ํ™•์ธํ•ด๋ณด์ž.

import HomeIcon from '@mui/icons-material/Home';
import SettingsIcon from '@mui/icons-material/Settings';
import { useNavigate } from 'react-router-dom';
// useKeycloak import
import { useKeycloak } from "@react-keycloak/web";
import UserInfo from './userinfo';

export default function MenuIcon(props) {
    const navigator = useNavigate()
    
    // Using Object destructuring
    const { keycloak } = useKeycloak();

    const handleIcon = (e) => {
        switch (e) {
            case 'A' : 
                // keycloak์— ๋กœ๊ทธ์ธ์ด ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด, keycloak ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ˜ธ์ถœ
                if (!keycloak.authenticated) {
                    alert("๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•œ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.")
                    // keycloak ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ˜ธ์ถœ์‹œ redirectUri๋ฅผ ๊ฐœ์ธํ™”๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
                    keycloak.redirectUri= window.location.href + '/manager'
                    // keycloak ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ˜ธ์ถœ
                    keycloak.login();
                }

            return navigator('/manager')
            
            case 'M' : return navigator('/')
            default : return navigator('/')
        }
    }
    return (
<>
      <div className='menu-wrap'>
        <div className='menu-box'>
          <HomeIcon fontSize='large' color="secondary"
             onClick={() => handleIcon('M')} 
          />
          <SettingsIcon fontSize='large' color="secondary"
             onClick={() => handleIcon('A')} 
          /> 
        </div>
      </div>      

//์ž„์‹œ๋กœ ๋ฐ˜์˜.. 
//๋กœ๊ทธ์ธ๋˜๋ฉด token๊ฐ’๊ณผ payload๊ฐ’์„ ๋ณด์—ฌ์ค€๋‹ค.

      { keycloak.idToken ?
          <UserInfo /> 
        : null
      }
</>
    )
}

 

menu.jsx ๋งˆ์ง€๋ง‰์— UserInfo ์ปจํฌ๋„ŒํŠธ๋ฅผ ์ž„์‹œ๋กœ ๋ฐ˜์˜ํ•œ๋‹ค.

 

      { keycloak.idToken ?
          <UserInfo /> 
        : null
      }

 

 

๊ทธ๋Ÿผ ๋กœ๊ทธ์ธ์„ ํ†ตํ•ด idToken๊ณผ Token , ๊ทธ๋ฆฌ๊ณ  payload๊ฐ’์„ ์ถœ๋ ฅํ•ด๋ณธ๋‹ค.

 

 

๋งํฌ์„œ๋น„์Šค ์‚ฌ์ดํŠธ์— ๋กœ๊ทธ์ธ์ด ๋˜์–ด token๊ฐ’๊ณผ playload์ •๋ณด๋ฅผ ๋ณผ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ, ๊ฐœ๋ฐœ์ž๋ชจ๋“œ console ์—์„œ๋Š” auth token๊ณผ refresh token์„ ๊ณ„์†์ ์œผ๋กœ ์ƒ์„ฑ๋จ์„ ํ™•์ธํ• ์ˆ˜ ์žˆ๋‹ค.

 

๋™์ผํ•˜๊ฒŒ  jwt.io ์‚ฌ์ดํŠธ์—์„œ๋„ ํ™•์ธํ•ด๋ณธ๋‹ค. 

๋‘๊ฐœ๋ฅผ ๋น„๊ตํ•ด๋ณด๋ฉด ๋™์ผํ•œ ๊ฒฐ๊ณผ๊ฐ’์ž„์„ ์•Œ์ˆ˜ ์žˆ๋‹ค.

 

 

๊ทธ๋Ÿผ token์ •๋ณด์—์„œ ๋กœ๊ทธ์ธ ์•„์ด๋””, ์ด๋ฆ„ ๋“ฑ ์ถœ๋ ฅํ• ๋•Œ๋Š” idTokenParsed ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๋ฉด ํ•œ๋‹ค.

 

์•„์ด๋”” ์ •๋ณด๋ฅผ ์•Œ๊ณ  ์‹ถ์„๋•Œ, 

keycloak.idTokenParsed.preferred_username

 

์œ„์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ payload๊ฐ’์„ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด ๋œ๋‹ค.

 

 

๊ทธ๋Ÿผ ๋‹ค์ŒํŽธ์— ๊ณ„์†..................................

 

 

 

+ Recent posts