如何在ASP.NET Core with React.JS模板中实现控制器与React组件的数据交互?
ASP.NET Core + React 数据传输与JWT认证实现方案
一、.NET Core 控制器与模型基础实现
1. 定义数据模型
在项目Models目录下创建用户相关实体和请求/返回DTO:
// User.cs(数据库实体) public class User { public int Id { get; set; } public string Username { get; set; } = string.Empty; public string Email { get; set; } = string.Empty; public string PasswordHash { get; set; } = string.Empty; } // LoginRequest.cs(登录请求参数) public class LoginRequest { public string Username { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; } // RegisterRequest.cs(注册请求参数) public class RegisterRequest { public string Username { get; set; } = string.Empty; public string Email { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; } // AuthResponse.cs(登录返回结果) public class AuthResponse { public string Token { get; set; } = string.Empty; public string Username { get; set; } = string.Empty; }
2. 编写认证控制器
创建AuthController.cs,处理登录、注册逻辑:
[ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly DataContext _context; private readonly IConfiguration _config; public AuthController(DataContext context, IConfiguration config) { _context = context; _config = config; } // 注册接口 [HttpPost("register")] public async Task<ActionResult<User>> Register(RegisterRequest request) { using var hmac = new HMACSHA512(); var user = new User { Username = request.Username, Email = request.Email, PasswordHash = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(request.Password))) }; _context.Users.Add(user); await _context.SaveChangesAsync(); return Ok(user); } // 登录接口 [HttpPost("login")] public async Task<ActionResult<AuthResponse>> Login(LoginRequest request) { var user = await _context.Users.FirstOrDefaultAsync(u => u.Username == request.Username); if (user == null) return Unauthorized("用户名错误"); using var hmac = new HMACSHA512(); var computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(request.Password)); if (!computedHash.SequenceEqual(Convert.FromBase64String(user.PasswordHash))) return Unauthorized("密码错误"); var token = CreateToken(user); return Ok(new AuthResponse { Token = token, Username = user.Username }); } // 生成JWT私有方法 private string CreateToken(User user) { var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.Username), new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()) }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config.GetSection("AppSettings:Token").Value!)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature); var token = new JwtSecurityToken( claims: claims, expires: DateTime.Now.AddDays(1), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); } }
二、配置JWT认证服务
在Program.cs中添加认证授权相关配置:
var builder = WebApplication.CreateBuilder(args); // 注册数据库上下文 builder.Services.AddDbContext<DataContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // 配置JWT认证 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration.GetSection("AppSettings:Token").Value!)), ValidateIssuer = false, ValidateAudience = false }; }); builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages(); var app = builder.Build(); // 中间件顺序不可乱 app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); // 先认证再授权 app.UseAuthentication(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller}/{action=Index}/{id?}"); app.MapFallbackToFile("index.html"); app.Run();
在appsettings.json中添加密钥和数据库连接配置:
{ "AppSettings": { "Token": "你的32位以上安全密钥" }, "ConnectionStrings": { "DefaultConnection": "你的SQL Server连接字符串" } }
三、React端数据交互实现
1. 登录组件(axios请求)
在ClientApp/src/components下创建Login.jsx:
import { useState } from 'react'; import axios from 'axios'; export default function Login() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const handleLogin = async (e) => { e.preventDefault(); try { const res = await axios.post('/api/auth/login', { username, password }); localStorage.setItem('token', res.data.token); localStorage.setItem('username', res.data.username); window.location.href = '/'; } catch (err) { alert(err.response.data); } }; return ( <form onSubmit={handleLogin}> <div> <label>用户名</label> <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} required /> </div> <div> <label>密码</label> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} required /> </div> <button type="submit">登录</button> </form> ); }
2. 注册组件示例
import { useState } from 'react'; import axios from 'axios'; export default function Register() { const [username, setUsername] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const handleRegister = async (e) => { e.preventDefault(); try { await axios.post('/api/auth/register', { username, email, password }); alert('注册成功,请登录'); window.location.href = '/login'; } catch (err) { alert(err.response.data); } }; return ( <form onSubmit={handleRegister}> <div> <label>用户名</label> <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} required /> </div> <div> <label>邮箱</label> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required /> </div> <div> <label>密码</label> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} required /> </div> <button type="submit">注册</button> </form> ); }
3. 受保护路由与授权请求
在App.jsx中配置路由保护:
import { Routes, Route, Navigate } from 'react-router-dom'; import Login from './components/Login'; import Register from './components/Register'; import Dashboard from './components/Dashboard'; const ProtectedRoute = ({ children }) => { const token = localStorage.getItem('token'); return token ? children : <Navigate to="/login" />; }; function App() { return ( <Routes> <Route path="/login" element={<Login />} /> <Route path="/register" element={<Register />} /> <Route path="/" element={ <ProtectedRoute> <Dashboard /> </ProtectedRoute> } /> </Routes> ); } export default App;
在Dashboard.jsx中请求授权接口:
import { useState, useEffect } from 'react'; import axios from 'axios'; export default function Dashboard() { const [forecasts, setForecasts] = useState([]); useEffect(() => { const fetchData = async () => { try { const token = localStorage.getItem('token'); const res = await axios.get('/weatherforecast', { headers: { Authorization: `Bearer ${token}` } }); setForecasts(res.data); } catch (err) { alert('请重新登录'); window.location.href = '/login'; } }; fetchData(); }, []); return ( <div> <h1>欢迎 {localStorage.getItem('username')}</h1> <ul> {forecasts.map(f => ( <li key={f.date}> {f.date}: {f.summary} - {f.temperatureC}°C </li> ))} </ul> </div> ); }
最后给WeatherForecast控制器添加授权特性:
[Authorize] [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { // 原有代码... }
内容的提问来源于stack exchange,提问作者Việt Tùng Nguyễn
相关产品推荐
相关产品推荐

