上篇博客,当没有权限的用户访问一些资源时,返回的是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 {  get private  set ; }
             public  string  Message {  get private  set ; }
             public  string  Details {  get private  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" ];
             };
         }
     }
}