简体   繁体   中英

Web Api routing trouble

I have an self hosted Web API project, so I had to use Yao's blog post to make help page work. Next, I've had to secure some of my methods from unauthorized use. I've implemented this idea .

Now the fun part. I have 3 routes:

/help which leads to Help Page,

/authentication/authenticate is used to call authentication method and it expects user credentials and returns security token in case of success

and /transaction/{action}/{id} this route needs to be secured from unauthorized use.

So basically, I need to make all routes, where controller = transaction, to be processed by TokenInspector .

1. Scenario: if I have routing configuration like this:

_config.Routes.MapHttpRoute(
            name: "AuthenticatedOnly",
            routeTemplate: "transaction/{action}/{id}",
            defaults: new {controller = "Transaction", action="GetNewTaskId", id=RouteParameter.Optional},
            constraints: null,
            handler: tokenInspector
            );

        _config.Routes.MapHttpRoute(
            "Default",
            "{controller}/{action}/{id}",
            defaults: new { controller="Help", action="Index", id = RouteParameter.Optional}
            );

Everything works fine, except Help page shows only POST Authentication/Authenticate entry

2. Scenario: if I change routing config to:

_config.Routes.MapHttpRoute(
            name: "AuthenticatedOnly",
            routeTemplate: "transaction/{action}/{id}",
            defaults: new {},
            constraints: null,
            handler: tokenInspector
            );

        _config.Routes.MapHttpRoute(
            "Default",
            "{controller}/{action}/{id}",
            defaults: new { controller="Help", action="Index", id = RouteParameter.Optional}
            );

Help page works fine and shows all the methods, but /transaction is not secured anymore and is working without token.

3. Scenario:

_config.Routes.MapHttpRoute(
                name: "AuthenticatedOnly",
                routeTemplate: "transaction/{action}/{id}",
                defaults: new {id=RouteParameter.Optional},
                constraints: null,
                handler: tokenInspector
                );

            _config.Routes.MapHttpRoute(
                "Default",
                "{controller}/{action}/{id}",
                defaults: new { controller="Help", action="Index", id = RouteParameter.Optional}
                );

Works both authentication and help page, but when I make request like /Transaction/GetNewTaskId with valid Token in it's header, I get 404.

Update Could anyone explain, how help page generation depends on registered routes? Is there any way to tweak it and enforce ApiExplorer to print out controller contained stuff?

Update 2 After some more struggling and investigating, I found a solution, which matches my goal - to keep documentation as well as security pattern. I've implemented a custom message handler (basically, I used my TokenInspector, but added url filtering to it's logic).

So, I have single route now:

_config.Routes.MapHttpRoute(
                name: "Default",
                routeTemplate: "{controller}/{action}/{id}",
                defaults: new { controller = "Help", action = "Index", id=RouteParameter.Optional }
                );

and this is how I launch the server:

_config = new ExtendedHttpSelfHostConfiguration(ServiceAddress);
            TokenInspector tokenInspector = new TokenInspector() { InnerHandler = new HttpRoutingDispatcher(_config) };
            _server = new HttpSelfHostServer(_config, tokenInspector);
            ConfigureHost(_config);
            _server.OpenAsync();

Probably, the question as it was, could not be answered in this way, but anyway, thank you all for your effort!

Regards, insomnium_

//This is for your public controllers
//this route will ONLY catch requests for Help and Authentication controllers only
//you will need to include any new public controller that uses the route pattern
_config.Routes.MapHttpRoute(
    name: "Public",
    routeTemplate: "{controller}/{action}/{id}",
    constraints: new  { controller = @"^(Help|Authentication)$" },
    defaults: new { controller="Help", action="Index", id = RouteParameter.Optional}
);


//Everything that is not Help or Authentication will use this route, which will check for the valid token you mention
//This route is defaulting to /Transaction/GetNewTaskId    
_config.Routes.MapHttpRoute(
     name: "AuthenticatedOnly",
     routeTemplate: "{controller}/{action}/{id}",
     defaults: new { controller = "Transaction", action="GetNewTaskId", id=RouteParameter.Optional},
     handler: tokenInspector
);

Use this approach for more flexible method access management

config.Routes.MapHttpRoute(
   name: "PublicMethods",
   routeTemplate: "api/{controller}/{action}",
   constraints: new {action = @"^(public)-(.)*$"},
   defaults: new {controller = "Account"}
);

config.Routes.MapHttpRoute(
   name: "PublicControllers",
   routeTemplate: "api/{controller}/{action}",
   constraints: new {controller = @"^(Environment|Account)$"},
   defaults: new {controller = "Account"}
);

config.Routes.MapHttpRoute(
   name: "AuthorizedUsersOnly",
   routeTemplate: "api/{controller}/{action}/{id}",
   defaults: new { id = RouteParameter.Optional },
   constraints: null,
   handler: tokenInspector
);

So I have few open for each user controllers and if it's necessary I make some methods accessible for not authorized users by adding 'public' prefix to action name

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM