feat(auth): implement cookie-based token management and update user ID retrieval

This commit is contained in:
ShiYu
2025-06-09 23:57:16 +08:00
parent f7048c3025
commit dbe306d2df
5 changed files with 77 additions and 3 deletions

View File

@@ -1,6 +1,9 @@
using Microsoft.AspNetCore.Mvc;
using Foxel.Models;
using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace Foxel.Controllers
{
@@ -14,6 +17,37 @@ namespace Foxel.Controllers
return userIdClaim != null ? int.Parse(userIdClaim) : null;
}
protected int? GetUserIdFromCookie()
{
try
{
var token = Request.Cookies["token"];
if (string.IsNullOrEmpty(token))
{
return null;
}
var tokenHandler = new JwtSecurityTokenHandler();
if (!tokenHandler.CanReadToken(token))
{
return null;
}
var jwtToken = tokenHandler.ReadJwtToken(token);
var userIdClaim = jwtToken.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;
if (userIdClaim != null && int.TryParse(userIdClaim, out var userId))
{
return userId;
}
}
catch (Exception)
{
return null;
}
return null;
}
protected ActionResult<BaseResult<T>> Success<T>(T data, string message = "操作成功", int statusCode = 200)
{
return Ok(new BaseResult<T>

View File

@@ -273,7 +273,7 @@ public class PictureController(IPictureService pictureService, IStorageService s
_logger.LogWarning("GetPictureFile: Picture with ID {PictureId} not found.", pictureId);
return NotFound("Picture not found.");
}
var currentUserId = GetCurrentUserId();
var currentUserId = GetUserIdFromCookie();
if (picture.Permission != PermissionType.Public)
{
if (currentUserId == null || picture.UserId != currentUserId.Value)

View File

@@ -5,7 +5,6 @@ using Foxel.Models.DataBase;
using Foxel.Models.Request.Auth;
using Foxel.Services.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using static Foxel.Utils.AuthHelper;

View File

@@ -43,6 +43,17 @@ const customTheme = {
itemHoverColor: '#333333',
itemBorderRadius: 8,
},
Table: {
rowSelectedBg: '#f8f9fa',
rowSelectedHoverBg: '#e9ecef',
rowHoverBg: '#fafbfc',
headerBg: '#ffffff',
headerColor: '#495057',
colorBgContainer: '#ffffff',
colorText: '#212529',
colorTextHeading: '#343a40',
borderColor: '#dee2e6',
},
}
};

View File

@@ -4,6 +4,7 @@ import { type UserRole } from './userManagementApi';
// 认证数据本地存储键
const TOKEN_KEY = 'token';
const USER_KEY = 'user';
const COOKIE_TOKEN_KEY = 'token';
// 登录请求参数
export interface LoginRequest {
@@ -53,6 +54,28 @@ export interface BindAccountRequest {
thirdPartyUserId: string;
}
// Cookie操作辅助函数
const setCookie = (name: string, value: string, days: number = 7): void => {
const expires = new Date();
expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
};
const getCookie = (name: string): string | null => {
const nameEQ = name + "=";
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
};
const deleteCookie = (name: string): void => {
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/;SameSite=Lax`;
};
// 用户注册
export async function register(data: RegisterRequest): Promise<BaseResult<AuthResponse>> {
return fetchApi<AuthResponse>('/auth/register', {
@@ -156,6 +179,7 @@ export async function bindAccount(data: BindAccountRequest): Promise<BaseResult<
// 保存认证数据到本地存储
export const saveAuthData = (authData: AuthResponse): void => {
localStorage.setItem(TOKEN_KEY, authData.token);
setCookie(COOKIE_TOKEN_KEY, authData.token, 7); // 保存7天
if (authData.user) {
localStorage.setItem(USER_KEY, JSON.stringify(authData.user));
}
@@ -165,6 +189,7 @@ export const saveAuthData = (authData: AuthResponse): void => {
export const clearAuthData = (): void => {
localStorage.removeItem(TOKEN_KEY);
localStorage.removeItem(USER_KEY);
deleteCookie(COOKIE_TOKEN_KEY);
};
// 检查是否已认证
@@ -186,7 +211,12 @@ export const getStoredUser = (): UserProfile | null => {
// 获取存储的令牌
export const getToken = (): string | null => {
return localStorage.getItem(TOKEN_KEY);
// 优先从localStorage获取
const localToken = localStorage.getItem(TOKEN_KEY);
if (localToken) return localToken;
// 备用从cookies获取
return getCookie(COOKIE_TOKEN_KEY);
};
// 处理GitHub OAuth回调接收token并保存