MVC 4 Web API基础认证实现求助:模拟REST服务认证流程
实现MVC4 Web API的基础认证+会话令牌机制
我来帮你搞定这个认证逻辑的问题~先梳理下你的核心需求:
- 第一步:客户端通过
/api/authenticate接口,用Basic认证(请求头带Authorization Basic [base64编码的用户名:密码])获取会话令牌 - 第二步:后续请求在自定义X头里携带该令牌完成身份校验
接下来针对你的代码问题,一步步完善:
1. 完善认证接口(/api/authenticate)
你当前的Post方法有几个可以优化的点,比如直接操作System.Web.HttpContext.Current不够贴合Web API的设计,而且WebSecurity是ASP.NET Web Pages的工具,不太适合Web API场景。我们改成更规范的写法:
using System; using System.Text; using System.Net; using System.Web.Http; public class AuthenticateController : ApiController { public IHttpActionResult Post() { // 检查是否存在合法的Basic认证头 if (Request.Headers.Authorization == null || Request.Headers.Authorization.Scheme != "Basic") { // 返回401并触发浏览器的Basic认证提示 return Unauthorized(); } // 解码Basic认证参数 string authToken = Request.Headers.Authorization.Parameter; string decodedToken = Encoding.UTF8.GetString(Convert.FromBase64String(authToken)); string[] credentials = decodedToken.Split(':'); // 校验认证格式是否合法 if (credentials.Length != 2) { return BadRequest("无效的认证格式"); } string username = credentials[0]; string password = credentials[1]; // 校验用户名密码(这里可以替换成你的数据库校验逻辑) if (username == "MyApiUserName" && password == "MyApiPassword") { // 生成会话令牌:用Guid足够简单,也可以考虑JWT(MVC4环境下Guid更易实现) string sessionToken = Guid.NewGuid().ToString("N"); // 存储令牌:示例用HttpContext.Cache,单服务器场景够用;多服务器建议用Redis/数据库 System.Web.HttpContext.Current.Cache.Insert( sessionToken, username, null, DateTime.Now.AddHours(2), // 设置2小时过期 TimeSpan.Zero ); // 返回200状态码和令牌JSON return Ok(new { Token = sessionToken }); } else { // 用户名密码错误,返回401 return Unauthorized(); } } }
2. 实现后续请求的令牌校验
我们可以写一个ActionFilterAttribute来统一校验X头里的令牌,避免每个接口都写重复代码:
using System.Linq; using System.Web.Http.Filters; using System.Net; using System.Net.Http; public class TokenAuthorizeAttribute : ActionFilterAttribute { public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) { // 跳过认证接口的校验,避免死循环 if (actionContext.ControllerContext.ControllerDescriptor.ControllerName == "Authenticate" && actionContext.ActionDescriptor.ActionName == "Post") { base.OnActionExecuting(actionContext); return; } // 从自定义X头获取令牌(示例头名为X-Session-Token) string sessionToken = null; if (!actionContext.Request.Headers.TryGetValues("X-Session-Token", out var tokenValues)) { actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized) { Content = new StringContent("请提供会话令牌") }; return; } sessionToken = tokenValues.FirstOrDefault(); // 校验令牌是否有效(从之前存储的位置读取) var username = System.Web.HttpContext.Current.Cache.Get(sessionToken); if (username == null) { actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized) { Content = new StringContent("无效或过期的会话令牌") }; return; } // 将用户名存入请求上下文,后续接口可以直接调用 actionContext.Request.Properties["Username"] = username.ToString(); base.OnActionExecuting(actionContext); } }
3. 应用令牌校验过滤器
有两种方式应用这个过滤器:
- 全局应用:在
WebApiConfig.cs里注册,所有接口都会被校验(除了我们跳过的认证接口)
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // 注册全局令牌校验过滤器 config.Filters.Add(new TokenAuthorizeAttribute()); // 常规路由配置 config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
- 局部应用:只给需要校验的控制器/方法添加
[TokenAuthorize]特性
[TokenAuthorize] public class ValuesController : ApiController { // 你的业务接口方法... }
几个生产环境注意点
- 令牌存储:多服务器部署时,不要用
HttpContext.Cache,换成Redis或者数据库来存储令牌和过期时间 - 安全性:不要硬编码用户名密码,一定要从数据库或者加密配置文件读取
- 令牌过期:可以根据业务需求调整过期时间,也可以实现令牌刷新机制
- 错误处理:建议把错误信息封装成统一的JSON格式,方便客户端解析
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

