iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
永豐金融APIs

30天全端挑戰!React+Spring Boot+Mongo DB 串接永豐API 打造金融網站系列 第 26

[Day 26] - React 前端串後端 - 串接登入

經過一整天的奮鬥,終於跟React稍微熟了一點

首先建一個apiUtil.js
我打算把跟後端相關的方法都集中在這邊做管理
先從登入開始
這邊就是拿使用者輸入的email、登入帳號、密碼,用axios丟到後端登入api

import axios from "axios";

const userRequest = axios.create({
    baseURL: 'http://localhost:8080',
    headers: { 'Content-Type': 'application/json' },
  })

export const login = (email,userAccount, userPassword) => {
    return userRequest.post("/demo/api/v1/user/login",
    JSON.stringify({
        email,
        userAccount,
        userPassword,})
        ).then((res) => res.data).catch((err)=>err.toString());
  };

再來,建立一個Login.js,這支是拿來放登入頁面的component

import React, { useState } from 'react';
import { login } from "../util/auth";
import { setAuthToken } from "../util/auth";
import { useHistory } from "react-router-dom";


const Login =() => {
  const [useremail, setUseremail] = useState("");
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [errorMessage, setErrorMessage] = useState("");
  const [loading, setLoading] = useState(false);

  const handleLogin = (e) => {
    setLoading(true);
    setErrorMessage(null);
    login(useremail,username, password).then((data) => {
      if (data.token ==null) {
        setLoading(false);
        return setErrorMessage(data.status);
      }
      setLoading(false);
    });
  };

  const handleUseremail = (e) => {
    setUseremail(e.target.value);
  };
  const handleUsername = (e) => {
    setUsername(e.target.value);
  }; 

  const handlePassword = (e) => {
    setPassword(e.target.value);
  };


    return(
        <div className="hero min-h-screen bg-base-200">
  <div className="flex-col justify-center hero-content lg:flex-row">
    <div className="text-center lg:text-left">
      <h1 className="mb-5 text-5xl font-bold">
            IT鐵人賽
          </h1> 
      <p className="mb-5">
      30天全端挑戰!React+Spring Boot+Mongo DB 串接永豐API 打造金融網站 
          </p>
    </div> 
    <div className="card flex-shrink-0 w-full max-w-sm shadow-2xl bg-base-100">
      <div className="card-body">
        <div className="form-control">
          <label className="label">
            <span className="label-text">信箱</span>
          </label> 
          <input type="text" placeholder="email" className="input input-bordered" value={useremail} onChange={handleUseremail}/>
        </div> 
        <div className="form-control">
          <label className="label">
            <span className="label-text">帳號</span>
          </label> 
          <input type="text" placeholder="account" className="input input-bordered" value={username} onChange={handleUsername}/>
        </div>         
        <div className="form-control">
          <label className="label">
            <span className="label-text">密碼</span>
          </label> 
          <input placeholder="password" className="input input-bordered" type="password" value={password} onChange={handlePassword}/> 
          <label className="label">
          </label>
        </div> 
        {errorMessage && <><small style={{ color: 'red' }}>{errorMessage}</small><br /></>}<br/>
        <div className="form-control mt-6">
          <input type="button" className="btn btn-primary" value={loading ? '登入中...' : '登入'} onClick={handleLogin} disabled={loading} />
          
        </div>
      </div>
    </div>
  </div>
</div>
        )
    }
    export default Login        

這邊就是把使用者輸入的值做綁定,輸入完之後,如果按登入就會觸發事件把資料藉由前面在apiUtil寫的方法帶到api

因為我在登入api有做調整,改成回json格式,
登入成功的話會帶status跟token兩個值
失敗的話就只會帶status,
所以我在這邊以data.token是否存在來判斷有沒有登入成功,
登入失敗的話就會把status秀出來在頁面上

Login.js寫好之後,就拿它來取代原本在index.js的<APP/>
在index.js引入import Login from './components/Login'之後
就可以把<APP/>換成<Login/>
這麼一來React的預設畫面就會被換成剛剛寫好的登入頁了
https://ithelp.ithome.com.tw/upload/images/20211011/20128973WURAR093kI.png
寫完之後就來試試

https://ithelp.ithome.com.tw/upload/images/20211011/201289738egILcNQ5y.png
又遇到了熟悉的CORS問題/images/emoticon/emoticon10.gif

這裡要回到Spring Boot後端
上次新增的WebSecurityConfig.java去增加CORS的設定
允許localhost:3000連到這個Spring Boot的後端取資料

import java.util.Arrays;
import com.rei1997.vault.util.filter.AuthorizationCheckFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import static org.springframework.security.config.Customizer.withDefaults;


@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(HttpSecurity http) throws Exception {
 
        http.csrf().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.addFilterBefore(new AuthorizationCheckFilter(), BasicAuthenticationFilter.class);
        http.cors(withDefaults());//增加這行
    }  
    
    //增加這個bean
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(
        Arrays.asList("http://localhost:3000"));
        configuration.setAllowedMethods(
        Arrays.asList("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(
        Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;

    }

}

再來試試,
故意輸入錯誤的密碼,因為登入成功後的動作我還沒寫好
https://ithelp.ithome.com.tw/upload/images/20211011/2012897366vPGXjsB9.png
頁面顯示0003
https://ithelp.ithome.com.tw/upload/images/20211011/201289738BdfYFw1hX.png
沒錯,就是密碼錯誤

測試成功,接下來就試著把登入成功後得到的token存到cookie或者localstorage裡面
然後要在每次對後端api發request時帶上著個token以通過驗證/images/emoticon/emoticon13.gif


上一篇
[Day 25] - React + Tailwind CSS + DasyUI
下一篇
[Day 27] - React 前端串後端 - Cookie存取
系列文
30天全端挑戰!React+Spring Boot+Mongo DB 串接永豐API 打造金融網站30

尚未有邦友留言

立即登入留言