224 lines
6.0 KiB
Go
224 lines
6.0 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"ca-mini/internal/config"
|
|
"ca-mini/pkg/utils"
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
type LoginRequest struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
type TokenInfo struct {
|
|
Token string `json:"access_token"`
|
|
}
|
|
|
|
type UserInfo struct {
|
|
Name string `json:"name"`
|
|
Introduction string `json:"introduction"`
|
|
Avatar string `json:"avatar"`
|
|
Roles []string `json:"roles"`
|
|
}
|
|
|
|
type LoginResponse struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
Date string `json:"date"`
|
|
Data TokenInfo `json:"data"`
|
|
}
|
|
type LogutResponse struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
type UserInfoResponse struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
Date string `json:"date"`
|
|
Data UserInfo `json:"data"`
|
|
}
|
|
|
|
// Token 是返回的 Token 结构体
|
|
type Token struct {
|
|
TokenType string `json:"token_type,omitempty"`
|
|
ExpiresIn int64 `json:"expires_in,omitempty"`
|
|
AccessToken string `json:"access_token,omitempty"`
|
|
RefreshToken string `json:"refresh_token,omitempty"`
|
|
}
|
|
|
|
type TokenResponse struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
Date string `json:"date"`
|
|
Data Token `json:"data"`
|
|
}
|
|
|
|
// IssueCertificate 处理证书签发请求
|
|
func Login(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// 解析CSR请求
|
|
var loginRequest LoginRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&loginRequest); err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// 检查用户
|
|
if !CheckUser(loginRequest) {
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
// 生成Token
|
|
token, err := utils.GenerateRandomString(32)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to generate token: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
// 返回Token信息
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
w.WriteHeader(http.StatusOK)
|
|
response := LoginResponse{
|
|
Code: http.StatusOK,
|
|
Message: "Login successful",
|
|
Date: time.Now().Format(time.RFC3339),
|
|
Data: TokenInfo{Token: token},
|
|
}
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func Logout(w http.ResponseWriter, r *http.Request) {
|
|
// 这里可以添加注销逻辑,例如清除用户会话等
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
w.WriteHeader(http.StatusOK)
|
|
response := LogutResponse{
|
|
Code: http.StatusOK,
|
|
Message: "Logout successful",
|
|
}
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
// CheckBlacklist 处理黑名单查询请求
|
|
func CheckUser(login LoginRequest) bool {
|
|
if login.Username == "admin" && login.Password == "111111" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func GetUserInfo(w http.ResponseWriter, r *http.Request) {
|
|
// 假设用户信息存储在某个地方,这里直接返回一个示例用户信息
|
|
userInfo := UserInfo{
|
|
Name: "Admin User",
|
|
Introduction: "This is an admin",
|
|
Avatar: "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif",
|
|
Roles: []string{"admin"},
|
|
}
|
|
// 返回Token信息
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
w.WriteHeader(http.StatusOK)
|
|
response := UserInfoResponse{
|
|
Code: http.StatusOK,
|
|
Message: "Login successful",
|
|
Date: time.Now().Format(time.RFC3339),
|
|
Data: userInfo,
|
|
}
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func AuthCallBack(w http.ResponseWriter, r *http.Request) {
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
log.Fatalf("failed to load oauth config: %v", err)
|
|
}
|
|
|
|
// 从 URL 中提取 authorization code
|
|
code := r.URL.Query().Get("code")
|
|
if code == "" {
|
|
http.Error(w, "Missing authorization code", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// 构造 Basic Auth header
|
|
auth := cfg.OAuth.CLIENT_ID + ":" + cfg.OAuth.CLIENT_SECRET
|
|
authHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
|
|
|
|
// 构造请求体
|
|
formData := url.Values{}
|
|
formData.Add("grant_type", "authorization_code")
|
|
formData.Add("redirect_uri", cfg.OAuth.REDIRECT_URI)
|
|
formData.Add("client_id", cfg.OAuth.CLIENT_ID)
|
|
formData.Add("code", code)
|
|
|
|
// 创建请求
|
|
tokenURL := cfg.OAuth.AUTHORIZATION_SERVER_HOST + cfg.OAuth.TOKEN_URL
|
|
req, err := http.NewRequestWithContext(context.Background(), "POST", tokenURL, bytes.NewBufferString(formData.Encode()))
|
|
if err != nil {
|
|
log.Printf("Error creating request: %v", err)
|
|
http.Error(w, "Failed to create token request", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// 设置请求头
|
|
req.Header.Set("Authorization", authHeader)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
// 发送请求
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
log.Printf("Unexpected error while fetching token: %v", err)
|
|
http.Error(w, "Failed to fetch token", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// 读取响应体
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
log.Printf("Error reading response body: %v", err)
|
|
http.Error(w, "Failed to read token response", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
log.Printf("Error while fetching token: %s, response body: %s", resp.Status, body)
|
|
http.Error(w, fmt.Sprintf("Token request failed: %s", resp.Status), resp.StatusCode)
|
|
return
|
|
}
|
|
|
|
// 解析 JSON 到 Token 结构体
|
|
var token Token
|
|
if err := json.Unmarshal(body, &token); err != nil {
|
|
log.Printf("Error unmarshalling token response: %v", err)
|
|
http.Error(w, "Failed to parse token response", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// 返回 Token 信息
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
w.WriteHeader(http.StatusOK)
|
|
response := TokenResponse{
|
|
Code: http.StatusOK,
|
|
Message: "Login successful",
|
|
Date: time.Now().Format(time.RFC3339),
|
|
Data: token,
|
|
}
|
|
if err := json.NewEncoder(w).Encode(response); err != nil {
|
|
log.Printf("Error encoding JSON response: %v", err)
|
|
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
|
}
|
|
}
|