AuthorizationFilter身份验证信息

最近被跨域问题搞得焦头烂额,在前端ajax往服务器端发送请求的时候,我尝试在请求报文header里面自定义请求头:

$.ajax({
         type: "GET",
         url: 'http://localhost:49420/api/v1/User/GetById?id=1',
         dataType: "json",
         headers: {
             AppKey: "fasdf2236afasdZ98",
             Sign: "6930718a6a0395349c20b9b409a52c72"
         },
         success: function(data, status) {},
         error: function(error) {}
     });

后端服务器:

 
 IEnumerable<string> appKeys;
            if (!actionContext.Request.Headers.TryGetValues("AppKey",out appKeys)) 
                   { 
                    return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized)
                   {
                       Content = new StringContent("报文头中的AppKey为空")
                   };
            }

可是本来以为这样写没问题,可是浏览器端一直给我返401:Unauthorized错误,并且提示 已拦截跨源请求:同源策略禁止读取远程资源。(原因:CORS 请求未能成功)

各种方法尝试了,未果。。。。

之后发现是服务器端未验证通过客户端的methods,需要在AuthorizationFilter过滤器的最开始,验证请求报文的方法是不是options,如果不是直接打回,是的话返回200:Accepted,然后进行后面AuthorizationFilter的验证。

string method = actionContext.Request.Method.ToString();
            if (method == "OPTIONS")
            {
                return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
            }

注意:必须给浏览器返回一个200码,才能进行自定义头部信息的验证

※另外:必须在配置文件中"Access-Control-Allow-Headers"的值中加上“appkey,sign”。表示允许接收报文头部的appkey,sign。不设置的话报以下错误

已拦截跨源请求:同源策略禁止读取位于 ****的远程资源。(原因:来自 CORS 预检通道的 CORS 头 ‘Access-Control-Allow-Headers’ 的令牌 ‘appkey’ 无效)。

总之,对症下药就好了~~

最后附上AuthorizationFilter过滤器的完整代码和我的解决跨域问题配置文件这一块的代码,仅供参考。

using RuPeng.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using UserCenter.IServices;

namespace UserCenter.OpenAPI.Filters
{
    public class UCAuthorizationFilter : IAuthorizationFilter

    {
        //一个对象必须是IOC容器创建出来的,才能注入
        public IAppInfoService appInfoService { get; set; }
        public bool AllowMultiple => true;

        public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
        {
            string method = actionContext.Request.Method.ToString();
            if (method == "OPTIONS")
            {
                return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
            }
            //获得报文头中的AppKey和Sign
            IEnumerable<string> appKeys;
            if (!actionContext.Request.Headers.TryGetValues("AppKey",out appKeys)) 
                   { 
                    return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized)
                   {
                       Content = new StringContent("报文头中的AppKey为空")
                   };
            }
            IEnumerable<string> signs;
            if (!actionContext.Request.Headers.TryGetValues("Sign", out signs))
            {
                return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized)
                {
                    Content = new StringContent("报文头中的Sign为空")
                };
            }
            string appKey = appKeys.First();
            string sign = signs.First();
            var appInfo = await appInfoService.GetByAppKeyAsync(appKey);
            if (appInfo == null)
            {
                return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized)
                {
                    Content = new StringContent("不存在的AppKey")
                };
            }
            if (!appInfo.IsEnabled)
            {
                return new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
                {
                    Content = new StringContent("AppKey已经被封禁")
                };
            }
            //计算用户输入参数的连接+AppSecret的Md5值    
            //orderedQS就是按照key(参数的名字)进行排序的QueryString集合       
            var orderedQS = actionContext.Request.GetQueryNameValuePairs().OrderBy(kv => kv.Key);
            var segments =  orderedQS.Select(kv => kv.Key + "=" + kv.Value); //拼接key=value的数组 
            string qs = string.Join("&", segments);    //用&符号拼接起来     
            string computedSign = MD5Helper.ComputeMd5(qs + appInfo.AppSecret);//计算qs+secret 的md5值 

            //用户传进来md5值和计算出来的比对一下,就知道数据是否有被篡改过
            if (sign.Equals(computedSign,StringComparison.CurrentCultureIgnoreCase))
            {
                return await continuation();
            }
            else
            {
                return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized)
                { Content = new StringContent("sign验证失败") };
            }
          
        }
    }
}

<httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Content-Type" value="application/json"/>    
        <add name="Access-Control-Allow-Headers" value=" Content-Type,X-Requested-With,appkey,sign" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
      </customHeaders>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Security是一个用于身份验证和授权的框架,用于保护基于Spring的应用程序。它提供了一系列的过滤器、拦截器和安全注解,用于对用户进行认证和授权。 Spring Security的工作原理如下: 1. 用户请求访问受保护的资源,例如通过浏览器发送HTTP请求到应用程序的URL。 2. 请求到达Spring Security的过滤器链,该过滤器链会对请求进行拦截和处理。 3. 过滤器链中的第一个过滤器是`UsernamePasswordAuthenticationFilter`,它负责处理基于用户名和密码的身份验证。如果请求不包含身份验证信息身份验证失败,该过滤器将返回身份验证错误的响应。 4. 如果身份验证成功,Spring Security会创建一个`Authentication`对象,表示用户的身份信息,并将其存储在`SecurityContextHolder`中。 5. 过滤器链中的下一个关键过滤器是`AuthorizationFilter`,它负责检查用户是否有访问所请求资源的权限。它使用配置的访问规则(例如注解、配置文件)和用户的角色信息(存储在`Authentication`对象中)来进行授权判断。 6. 如果用户被授权访问资源,请求继续传递到应用程序中的相应处理程序进行处理。 7. 如果用户未被授权访问资源,`AuthorizationFilter`将返回一个授权错误的响应。 8. 应用程序处理完请求后,响应返回给用户。 总结来说,Spring Security通过过滤器链拦截请求并进行身份验证和授权,确保只有经过验证和授权的用户才能访问受保护的资源。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值