上篇博客,当没有权限的用户访问一些资源时,返回的是403错误,403对于用户来说是一个莫名其妙的数字,我们当然要处理成友好的提示。

关于错误处理,翻看了一下Nancy的源码,是这样处理的,见下面地址:

https://github.com/NancyFx/Nancy/blob/master/src/Nancy/ErrorHandling/DefaultStatusCodeHandler.cs

其实Nancy是允许我们采用相同的办法处理,现在把DefaultStatusCodeHandler.cs的源码复制下来,改成我们自己的CustomStatusCode.cs如下,关于详细说明,参考Nancy源码DefaultStatusCodeHandler.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using Nancy;
using Nancy.ErrorHandling;
using Nancy.ViewEngines;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Nancy.Responses.Negotiation;
using Nancy.Extensions;
using Nancy.IO;
  
namespace NancySelfHostWeb
{
    public class CustomStatusCode: IStatusCodeHandler
    {
         
        private const string DisableErrorTracesTrueMessage = "Error details are currently disabled. Please set <code>StaticConfiguration.DisableErrorTraces = false;</code> to enable.";
  
        private readonly IDictionary<HttpStatusCode, string> errorMessages;
        private readonly IDictionary<HttpStatusCode, string> errorPages;
        private readonly IResponseNegotiator responseNegotiator;
        private readonly HttpStatusCode[] supportedStatusCodes = { HttpStatusCode.Forbidden, HttpStatusCode.NotFound};
  
        public CustomStatusCode(IResponseNegotiator responseNegotiator)
        {
            this.errorMessages = new Dictionary<HttpStatusCode, string>
            {
                { HttpStatusCode.Forbidden, "查看是否有授权!" },
                { HttpStatusCode.NotFound, "找不到你要的资源!" }
  
            };
            this.errorPages = new Dictionary<HttpStatusCode, string>
            {
                { HttpStatusCode.Forbidden, LoadResource("NancySelfHostWeb.403.html") },
                { HttpStatusCode.NotFound, LoadResource("NancySelfHostWeb.404.html") }
  
            };
            this.responseNegotiator = responseNegotiator;
        }
         
        public bool HandlesStatusCode(HttpStatusCode statusCode, NancyContext context)
        {
            return this.supportedStatusCodes.Any(s => s == statusCode);
        }
  
        public void Handle(HttpStatusCode statusCode, NancyContext context)
        {
            if (context.Response != null && context.Response.Contents != null && !ReferenceEquals(context.Response.Contents, Response.NoBody))
            {
                return;
            }
            if (!this.errorMessages.ContainsKey(statusCode) || !this.errorPages.ContainsKey(statusCode))
            {
                return;
            }
            Response existingResponse = null;
            if (context.Response != null)
            {
                existingResponse = context.Response;
            }
            context.NegotiationContext = new NegotiationContext();
            var result = new DefaultStatusCodeHandlerResult(statusCode, this.errorMessages[statusCode], StaticConfiguration.DisableErrorTraces ? DisableErrorTracesTrueMessage : context.GetExceptionDetails());
            try
            {
                context.Response = this.responseNegotiator.NegotiateResponse(result, context);
                context.Response.StatusCode = statusCode;
  
  
                if (existingResponse != null)
                {
                    context.Response.ReasonPhrase = existingResponse.ReasonPhrase;
                }
                return;
            }
            catch (ViewNotFoundException)
            {
            }
            this.ModifyResponse(statusCode, context, result);
        }
  
  
        private void ModifyResponse(HttpStatusCode statusCode, NancyContext context, DefaultStatusCodeHandlerResult result)
        {
            if (context.Response == null)
            {
                context.Response = new Response { StatusCode = statusCode };
            }
            var contents = this.errorPages[statusCode];
            if (!string.IsNullOrEmpty(contents))
            {
                contents = contents.Replace("[DETAILS]", result.Details);
            }
            context.Response.ContentType = "text/html";
            context.Response.Contents = s =>
            {
                using (var writer = new StreamWriter(new UnclosableStreamWrapper(s), Encoding.UTF8))
                {
                    writer.Write(contents);
                }
            };
        }
        private static string LoadResource(string filename)
        {
  
            // 获取当前资源文件
            var resourceStream = typeof(CustomStatusCode).Assembly.GetManifestResourceStream(string.Format("{0}", filename));
            if (resourceStream == null)
            {
                return string.Empty;
            }
            using (var reader = new StreamReader(resourceStream))
            {
                return reader.ReadToEnd();
            }
        }
        internal class DefaultStatusCodeHandlerResult
        {
            public DefaultStatusCodeHandlerResult(HttpStatusCode statusCode, string message, string details)
            {
                this.StatusCode = statusCode;
                this.Message = message;
                this.Details = details;
            }
            public HttpStatusCode StatusCode { getprivate set; }
            public string Message { getprivate set; }
            public string Details { getprivate set; }
        }
    }
}


这样还可以把Nancy内置的500404错误改成我们自定义的显示。

 

有时觉得这样太麻烦,可以自大在Module中去判断登录用户是否具有角色,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using Nancy;
using Nancy.Security;
using System.Linq;
 
namespace TestSelfHostWeb.Modules
{
    public class IndexModule : NancyModule
    {
        public IndexModule()
        {
            //开启全局验证
            this.RequiresAuthentication();
            Get["/"] = parameters =>
            {
                //开启角色验证,只有该角色可以访问本路由
                //this.RequiresClaims("admin");
 
                //自己判断登录角色具有权限
                if (!this.Context.CurrentUser.Claims.Contains("admin"))
                {
                    return View["error"];//定义一个错误页面error.cshtml即可
                }
 
                return View["index"];
            };
        }
    }
}