侧边栏壁纸
  • 累计撰写 185 篇文章
  • 累计创建 77 个标签
  • 累计收到 17 条评论

目 录CONTENT

文章目录

C# RESTful Owin 自托管的Web API使用FORM实现身份验证

码峰
2022-10-10 / 0 评论 / 0 点赞 / 737 阅读 / 601 字 / 正在检测是否收录...
广告 广告

前言

RESTful Web API 使用Owin自托管的程序需要对客户端的访问做身份验证,可以使用FORM身份验证加Cookie来实现,缺点是由于使用了Cookie,不支持跨域的操作。

实现过程

定义FormAuthenticationFilterAttribute类

定义一个FormAuthenticationFilterAttribute,该类继承自AuthorizationFilterAttribute,并重写其OnAuthorization,在该方法中添加从请求头中获取有无登录的Cookie,若有则表示登录成功,否则失败,代码如下:

public class FormAuthenticationFilterAttribute : AuthorizationFilterAttribute
    {
        private const string UnauthorizedMessage = "Unauthorized";

        public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0)
            {
                base.OnAuthorization(actionContext);
                return;
            }

            var ctx = actionContext.Request.GetOwinContext();

            if (ctx.Request.User != null && ctx.Request.User.Identity.IsAuthenticated)
            {
                base.OnAuthorization(actionContext);
                return;
            }

            var cookies = actionContext.Request.Headers.GetCookies();
            if (cookies == null || cookies.Count < 1)
            {
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized) { Content = new StringContent(UnauthorizedMessage, Encoding.UTF8) };
                return;
            }

            FormsAuthenticationTicket ticket = GetTicket(cookies);
            if (ticket == null)
            {
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized) { Content = new StringContent(UnauthorizedMessage, Encoding.UTF8) };
                return;
            }

            if (ticket.Expired)
            {
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized) { Content = new StringContent(UnauthorizedMessage, Encoding.UTF8) };
                return;
            }
            
            base.OnAuthorization(actionContext);
        }

        private FormsAuthenticationTicket GetTicket(Collection<CookieHeaderValue> cookies)
        {
            FormsAuthenticationTicket ticket = null;
            foreach (var item in cookies)
            {
                var cookie = item.Cookies.SingleOrDefault(c => c.Name == FormsAuthentication.FormsCookieName);
                if (cookie != null)
                {
                    ticket = FormsAuthentication.Decrypt(cookie.Value);
                    break;
                }
            }
            return ticket;
        }

添加上述授权过滤器

FormAuthenticationFilterAttribute,也可在global文件中将该类添加到全局过滤器中,同时定义一个登录ACTION,用于登录入口,示例代码如下:

    [FormAuthenticationFilter]
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    [RoutePrefix("api/post/auth")]
    public class AuthController : ApiController
    {
        [AllowAnonymous]
        [HttpPost]
        [Route("login")]
        public HttpResponseMessage DoLogin(string token)
        {
            var context = Request.GetOwinContext();
            if ("admin".Equals(token, StringComparison.OrdinalIgnoreCase))
            {
                //创建票据
                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, token, DateTime.Now, DateTime.Now.AddMinutes(1), false, string.Empty);
                //加密票据
                string authTicket = FormsAuthentication.Encrypt(ticket);
                //存储为cookie               
                context.Response.Cookies.Append(FormsAuthentication.FormsCookieName, authTicket, 
                    new CookieOptions(){ Expires = DateTime.Now.Add(TimeSpan.FromMinutes(1))});
                return Request.CreateResponse(HttpStatusCode.OK, "登录成功!");
            }
            else
            {               
                return Request.CreateResponse(HttpStatusCode.Unauthorized, "登录失败!");
            }
        }

        [HttpGet]
        [Route("get-status")]
        public HttpResponseMessage GetStatus()
        {
            return Request.CreateResponse(HttpStatusCode.OK, "Authentication");
        }
    }

测试

可直接在浏览器中访问需要授权的方法(即:Login除外),如:http://192.168.1.100:8088/api/post/auth/get-status,响应结果如下:
image-1665402436617
可见,没有授权时返回了Unauthorized。

使用Postman进行测试,没有授权时,访问api/post/auth/get-status的响应结果如下:
image-1665402779695

授权,响应结果如下:
image-1665402841088

授权成功后,再访问api/post/auth/get-status的响应结果如下:
image-1665403190679

0
广告 广告

评论区