iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
Modern Web

前後端整合,用Spring boot 與React 開發屬於自己的記帳網頁系列 第 29

Day30 React前端登入串接與完賽心得

  • 分享至 

  • xImage
  •  

前言

最後一天了,經歷過前面29天的練習,相信大家對於前端、後端的開發方式,以及前後端整合的方式都已經有經驗了。在前面也已經教大家前端跟後端更進階的用法,最後就是來跟大家做最後的練習,再一次的前後端整合,來完成這次30天的挑戰
那就讓我們開始吧

LoginComponent.jsx創建

我們先到Component這個資料夾中創建LoginComponent.jsx
https://ithelp.ithome.com.tw/upload/images/20241003/20152864RbbdCPWXVR.png
再來,我們要再Servic這個資料夾中心曾AuthService
我們要來新增登入的方法,程式碼如下

AithService.js

import axios from "axios";
const AUTH_REST_API_BASE_URL = "http://localhost:8080/api/auth";
export const LoginAPICall = (username,password)=>axios.post(AUTH_REST_API_BASE_URL+'/login',{username, password});
export const storeToken = (token) => localStorage.setItem("token", token);
export const getToken = () => localStorage.getItem("token");
export const saveLoggedInUser =(username) =>  sessionStorage.setItem("authenticatedUser",username)
export const isUserLoggedIn = () =>{
    const username = sessionStorage.getItem("authenticatedUser")
    if(username == null)
    {
        return false;
    }
    else{
        return true;
    }
}
export const getLoggedInUser = () =>{
    const username = sessionStorage.getItem("authenticatedUser")
    return username
}

設置Login

完成之後,會到Login頁面,我們這次要使用到的是帳號密碼,當我們成功得到資料的時候,就會把網址轉到List清單中,這邊可以說是,我們把帳號密碼船過去的方式並不是直接傳送帳號密碼的資料,這樣子當被攔截的時候很不安全,所以我們會進行加密,把資料變成token的形式,而這個功能就會是這個程式碼

 const token = 'Basic ' + window.btoa(username + ':' + password);

完整的登入頁面如下

/* eslint-disable no-unused-vars */
import React, { useState } from 'react';
import { LoginAPICall, saveLoggedInUser, storeToken } from '../Service/AuthService';
import { useNavigate } from 'react-router-dom';

const LoginComponent = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const navigate = useNavigate();

  async function handleLoginForm(e) {
    e.preventDefault();

    LoginAPICall(username, password)
      .then((response) => {
        const token = 'Basic ' + window.btoa(username + ':' + password);
        console.log('token:' + token);
        storeToken(token);
        saveLoggedInUser(username);
        navigate('/list-account');
        window.location.reload(false); // 成功後重載頁面
      })
      .catch((error) => {
        console.log(error);
        // 如果登入失敗,顯示彈跳視窗
        window.alert('Login failed. Please check your username and password.');
      });
  }

  return (
    <div className='container'>
      <br />
      <br />
      <div className='row'>
        <div className='col-md-6 offset-md-3'>
          <div className='card'>
            <div className='card-header'>
              <h2 className='text-center'>Login</h2>
            </div>
            <div className='card-body'>
              <form>
                <div className='row mb-3'>
                  <label className='col-md-3 control-label'>Username</label>
                  <div className='col-md-9'>
                    <input
                      type='text'
                      name='username'
                      className='form-control'
                      placeholder='Enter username'
                      value={username}
                      onChange={(e) => setUsername(e.target.value)}
                    ></input>
                  </div>
                </div>
                <div className='row mb-3'>
                  <label className='col-md-3 control-label'>Password</label>
                  <div className='col-md-9'>
                    <input
                      type='password'
                      name='password'
                      className='form-control'
                      placeholder='Enter password'
                      value={password}
                      onChange={(e) => setPassword(e.target.value)}
                    ></input>
                  </div>
                </div>

                <div className='form-group mb-3'>
                  <button className='btn btn-primary' onClick={(e) => handleLoginForm(e)}>
                    Submit
                  </button>
                </div>
              </form>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default LoginComponent;

我們現在設置了登入的資料,但我們每調轉一次頁面,就要登入一次告訴後端我的權限,那這個樣子就會造成很大的困擾。我們在Service的時候有設置一個功能,是把登入的token存放在自己的網頁瀏覽器中,在我們每次跳轉頁面,後端要求我們提供登入帳號密碼的時候,只要從瀏覽器中再取得這個帳號密碼,提供給後端,這樣就不用使用者一直重複登入了。而這個由網頁提供帳密的方法,我們需要寫在每一個Service裡面,在開始執行登入前,就要進行這個動作
程式碼如下

axios.interceptors.request.use(function(config){
    config.headers['Authorization'] = getToken()
    //console.log("I'm here:"+getToken.toString)
    return config;
},function (error){
    return Promise.reject(error);
})

完整的程式碼會長這樣

import axios from "axios";
import { getToken } from "./AuthService";

const BASE_REST_API_URL = "http://localhost:8080/api/accounts"

axios.interceptors.request.use(function(config){
    config.headers['Authorization'] = getToken()
    //console.log("I'm here:"+getToken.toString)
    return config;
},function (error){
    return Promise.reject(error);
})

export const getAllAccounts = () => axios.get(BASE_REST_API_URL);

export const getAllCategories = ()=>axios.get(BASE_REST_API_URL+'/categories')

export const getAccountsByCategory = (category)=>axios.get(BASE_REST_API_URL+'/category/'+category)

export const getAccountsByWeek = (year,week)=>axios.get(BASE_REST_API_URL+'/weekly/'+year+"/"+week)

export const addAccount = (account) => axios.post(BASE_REST_API_URL,account);

export const getAccount = (id) => axios.get(BASE_REST_API_URL+'/'+id);

export const updateAccount = (id,todo) => axios.put(BASE_REST_API_URL+'/'+id,todo);

export const deleteAccount = (id)=>axios.delete(BASE_REST_API_URL+'/'+id);

寫完之後,我們回到App.jsx,把首頁改成LoginCompnent

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import HelloWorld from './Helloworld'
import HeaderComponent from './Component/HeaderComponent'
import FooterComponent from './Component/FooterComponent'
import AccountComponent from './Component/AccountComponent'
import ListAccountComponent from './Component/ListAccountComponent'
import { BrowserRouter, Routes,Route} from 'react-router-dom'
import SortAccountComponent from './Component/SortAccountComponent'
import WeeklyAccountComponent from './Component/WeeklyAccountComponent'
import ChartComponent from './Component/ChartComponent'
import LoginComponent from './Component/LoginComponent'


function App() {
  

  return (
    <>
    <BrowserRouter>
        <HeaderComponent />
        <Routes>
        {/* http://localhost:5173/ */}
        <Route path='/' element={<LoginComponent />}></Route>
          {/* http://localhost:5173/chart-account */}
          <Route path='/chart-account' element={<ChartComponent />}></Route>
          {/* http://localhost:5173/weekly-account' */}
          <Route path='/week-account' element={<WeeklyAccountComponent />}></Route>
          {/* http://localhost:5173/list-account */}
          <Route path='/list-account' element={<ListAccountComponent />}></Route>
          {/* http://localhost:5173/add-account */}
          <Route path='/add-account' element={<AccountComponent />}></Route>
          {/* http://localhost:5173/add-account/1 */}
          <Route path='/update-account/:id' element={<AccountComponent />}></Route>
          {/* http://localhost:5173/sort-account/ */}
          <Route path='/sort-account' element={<SortAccountComponent />}></Route>
        </Routes>
        <FooterComponent />
    </BrowserRouter>
    </>
  )
}

export default App

完成後再進入主頁,會看到這個畫面
https://ithelp.ithome.com.tw/upload/images/20241003/20152864kRix44lYge.png
接下來輸入Admin的帳號密碼,就會出現所有清單
https://ithelp.ithome.com.tw/upload/images/20241003/20152864jwFtbSDGbS.png
如果輸入的是User的帳號密碼,就會出現空白的清單
https://ithelp.ithome.com.tw/upload/images/20241003/20152864h4f9xBHIgE.png
到這裡,恭喜大家挑戰成功,完成從後端的Spring boot到前端的React開發,再加上設置了Spring boot Security跟React的登入畫面,完整的把前端跟後端的東西都學習透徹了!

完賽心得

30天說長不長,說短不短,在開賽的時候每到11點的PO文都是一個挑戰,每天都在擔心自己會不會沒有PO到文,而這三十天每天都在跟文章奮戰的日子,讓我覺得好像在跑一個長跑,需要持續而且用力的持續跑下去。

對於程式有興趣的我,藉由這三十天的練習,感覺自己更加了解前端與後端的概念,還有我覺得最難的Spring boot Security,在教學的過程中也明白了到底整個Security到底在做甚麼,當然我學習到的也只是皮毛,但比起三十天前的懵懂無知,感覺現在已經更加了解了一點。

感謝這三十天的挑戰,也感謝每年的比賽,讓我總能學習新東西,並且能夠讓自己變得更好一點!
期待我們明年見


上一篇
Day29 Spring boot security:後端登入API開發
下一篇
Day28 Spring boot Security:Login設定
系列文
前後端整合,用Spring boot 與React 開發屬於自己的記帳網頁30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言