refer: http://ip-api.com/
1.首先需要創建一個保存用戶歷史的登錄的表,然后連接go
2.在用戶登錄的時候,獲取用戶的IP IP位置,在后端直接處理數據即可(不需要在前端傳遞數據)
(1)增加路由:
apiv1.POST("/history_login_logs", v1.AddHistoryLoginLog)
(2)在model里增加(例如:models/history_login_logs.go)
?
func AddHistoryLoginLog(user_id int, ip_address string, ip_location string, login_at time.Time) bool {db.Create(&HistoryLoginLogs{UserId: user_id,IpAddress: ip_address,IpLocation: ip_location,LoginAt: login_at,})return true}
? (3) 在登錄后的方法中增加(需要引入
import("time""io/ioutil""fmt""encoding/json"
)type Location struct {Status string `json:"status"`Country string `json:"country"`CountryCode string `json:"countryCode"`Region string `json:"region"`RegionName string `json:"regionName"`City string `json:"city"`Zip string `json:"zip"`Lat float64 `json:"lat"`Lon float64 `json:"lon"`Timezone string `json:"timezone"`Isp string `json:"isp"`Org string `json:"org"`As string `json:"as"`Query string `json:"query"`
}...
ipAddress := c.ClientIP()
fmt.Println("== ip_address:", ipAddress)
resp, err := http.Get("http://ip-api.com/json/" + ipAddress + "?lang=zh-CN")
if err != nil {fmt.Println("Error:", err)return
}defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)if err != nil {fmt.Println("Error:", err)return}var location Location
err = json.Unmarshal(body, &location)if err != nil {fmt.Println("Error:", err)return}fmt.Println("=== Location:", location)
City := location.CitycurrentTime := time.Now()
models.AddHistoryLoginLog(user.ID, ipAddress, City, currentTime)
...
? (4)增加action (例如:routers/api/v1/history_login_log.go)(需要引入import? "net/http"?? "time"? "fmt")
?
type AddHistoryLoginLogRequest struct {UserID int `json:"user_id" binding:"required"`IPAddress string `json:"ip_address" binding:"required"`City string `json:"ip_location" binding:"required"`CurrentTime time.Time `json:"login_at" binding:"required"`}func AddHistoryLoginLog(c *gin.Context) {var request AddHistoryLoginLogRequestif err := c.ShouldBindJSON(&request); err != nil {fmt.Println("== err: ", err)return}models.AddHistoryLoginLog(request.UserID, request.IPAddress, request.City, request.CurrentTime)}
3.在前端寫一個展示的列表頁面即可。(登錄時間寫現在的時間即可。)
例如:src/pages/HistoryLoginLog/index.jsx
import React, { Component } from 'react'
import { Table } from 'antd';
import axios from 'axios'
import Config from '@/settings'
import { getToken, removeToken } from '@/utils/auth'const columns = [{title: '登錄名',dataIndex: 'user_id',key: 'user_id',render: text => <a>{text}</a>,},{title: '登陸時間',dataIndex: 'login_at',key: 'login_at',// 這里是進行時間的處理,轉換為北京時間,格式為:2023/08/16 21:40render: text => {const dateObj = new Date(text);const localizedDate = dateObj.toLocaleString('zh-CN', {timeZone: 'Asia/Shanghai',year: 'numeric',month: '2-digit',day: '2-digit',hour: '2-digit',minute: '2-digit',});return <span>{localizedDate}</span>;},},{title: '登陸ip',dataIndex: 'ip_address',key: 'ip_address',},{title: '登陸位置',dataIndex: 'ip_location',key: 'ip_locatio',}
];export default class CalculationPlan extends Component {state = {data: [],loading: true,}async fetchData() {try {const response = await axios.get(`${Config.BASE_URL}/api/v1/history_login_logs?token=${getToken()}`)if (response.data.message == "ok") {const sortedData = response.data.data.sort((a, b) => new Date(b.id) - new Date(a.id));this.setState({data: sortedData,loading: false,})}} catch (error) {console.error(error)removeToken()window.location.href = '/'}}componentDidMount() {this.fetchData()}render() {const { data, loading } = this.statereturn (<Table columns={columns} dataSource={data} loading={loading} />)}
}