How to grant access to only the routes defined? - asp.net-core

I have the following code defined in Startup.cs:
services.AddMvc().AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/ListVehicles", "/vehicle-list");
});
How do I only allow access to the page by using the url "vehicle-list" instead of just typing the cshtml file name ListVehicles in the url? I tried options.Conventions.Clear() but that didn't work.

You could achieve this with custom IPageRouteModelConvention that clears Selectors list in required PageRouteModel:
services.AddMvc().AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRouteModelConvention("/ListVehicles", model =>
{
model.Selectors.Clear();
});
options.Conventions.AddPageRoute("/ListVehicles", "vehicle-list");
});
Now request to http://localhost/ListVehicles will result to 404 error, while request to http://localhost/vehicle-list will return ListVehicles.cshtml page.

Related

GET Request fails in Vuejs Fetch but works perfectly in Postman and in browser due to 302 redirection

I have a web application built using NuxtJS/Vuejs within that I have a field where user can provide the URL and my application should make a GET request to that URL and obtain the data. Mostly the URL is related to GitHub from where it should fetch XML/JSON the data.
When I provide a certainly URL in browser/Postman then the redirection happens and data from the redirected URL is loaded. I want to achieve the same in my code but it's not happening and I get the error:
index.js:52 GET {{URL}} net::ERR_FAILED 302
But these URL works perfectly in browser and in Postman without any issue. Following is my code where I am making the request using Vuejs Fetch:
fetch(inputURL, {
method: 'GET'
})
.then((response) => {
console.log('RESPONSE')
console.log(response)
})
.catch((error) => {
console.log('ERROR')
console.log(error.response)
})
Using the Axios:
axios
.get(inputURL)
.then((response) => {
console.log("RESPONSE");
console.log(response);
})
.catch((error) => {
console.log("ERROR");
console.log(error);
})
I tried setting various header, I tried using axios etc but nothing seems to work for me. Can someone please explain to me what am I doing wrong and how to fix this issue? Any help or workaround would be really appreciated.
First of all, the 'Access-Control-Allow-Origin' header is something that should be set up on the server side, not on the client making the call. This header will come from the server to tell the browser to accept that response.
The reason why your code works from postman/browser is because you're not under the CORS rules when you request it like that.
One way around it, would be to make a call to your backend and tell the backend to call GET the data from the URL provided and then return it to your front-end.
Example:
//call_url.php
<?php
$url = $_GET['url'];
$response = file_get_contents($url);
echo $response
?>
//vue.js component
<input type="text" v-model="url"></input>
<button type="button" #click="callUrl">call me</button>
...
methods: {
callUrl() {
axios.get('call_url.php?url=' + encodeURIComponent(this.url))
.then(response => {
//...do something
}
}
}
As mentioned in another answer it's not possible for any library including Fetch and Axios to make requests and obtain the Data due to various security policies. Hence, I created a method in my Spring boot application that will obtain the data from URL and I make a request to my Spring boot using Axios.
import axios from 'axios'
axios.post('/urlDataReader', inputURL)
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
Spring boot app:
//Method to read the data from user-provided URL
#PostMapping(value = "/urlDataReader", produces = "text/plain")
public String urlDataReader(#RequestBody String inputURL) {
final String result = new RestTemplate().getForObject(inputURL, String.class);
return result;
}

How to use UseExceptionHandler in the mvc startup without redirecting the user?

I have a ASP.NET Core 2.1 MVC application, and I'm trying to return a separate html view when an exception occurs. The reason for this is that if there are errors, we don't want google to register the redirects to the error page for our SEO (I've omitted development settings to clear things up).
Our startup contained this:
app.UseExceptionHandler("/Error/500"); // this caused a redirect because some of our middleware.
app.UseStatusCodePagesWithReExecute("/error/{0}");
But we want to prevent a redirect, so we need to change the UseExceptionHandler.
I've tried to use the answer from this question like below:
app.UseExceptionHandler(
options =>
{
options.Run(
async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("sumtin wrong").ConfigureAwait(false);
});
});
But this gives a very ugly page without any styling. Another solution we've tried to use is creating an error handling middle ware, but there we run into the same problem there where we can't add a view.
How can I return a styled view in case of an exception, without redirecting the user?
EDIT: the UseExceptionHandler doesn't cause a redirect, it was caused by a bug in some of our middleware.
How can I return a styled view in case of an exception, without redirecting the user?
You're almost there. You could rewrite(instead of redirect) the path, and then serve a HTML according to current path.
Let's say you have a well-styled sth-wrong.html page in your wwwroot/ folder. Change the code as below:
app.UseExceptionHandler(appBuilder=>
{
// override the current Path
appBuilder.Use(async (ctx, next)=>{
ctx.Request.Path = "/sth-wrong.html";
await next();
});
// let the staticFiles middleware to serve the sth-wrong.html
appBuilder.UseStaticFiles();
});
[Edit] :
Is there anyway where I can make use of my main page layout?
Yes. But because a page layout is a View Feature that belongs to MVC, you can enable another MVC branch here
First create a Controllers/ErrorController.cs file :
public class ErrorController: Controller
{
public IActionResult Index() => View();
}
and a related Views/Error/Index.cshtml file:
Ouch....Something bad happens........
Add a MVC branch in middleware pipeline:
app.UseExceptionHandler(appBuilder=>
{
appBuilder.Use(async (ctx, next)=>{
ctx.Request.Path = "/Error/Index";
await next();
});
appBuilder.UseMvc(routes =>{
routes.MapRoute(
name: "sth-wrong",
template: "{controller=Error}/{action=Index}");
});
});
Demo:

asp.net core 2.1 custom default route per user

I'vew got an company internal website containing different areas implemented with asp.net core's area-logic.
I'd like to redirect the users to a homepage of their choice.
For Example:
User A: contonso.com/ showing index of area invoices
User B: contonso.com/ showing index of area customers
Possible workaround: Use a generic home controller that redirects the user to the appropriate area but i would like to know if there is a more generic solution using the build-in routing capabilities.
At the moment, i would stores those information in a database but actually i don't care how to configure, as long as I'm able to do the routing dynamically.
The docs and google doesn't say anything about this case.
Is there any way to get arround a custom middleware? Some buildin support, or an existing nuget-package?
You could try Middleware to redirect the requests based on your logic.
Here is a demo code for MVC Controller:
app.Use(async (context, next) =>
{
if (context.Request.Path == "/" && context.User.Identity.Name == "test#outlook.com")
{
context.Response.Redirect("Home/About", true);
}
else if (context.Request.Path == "/" && context.User.Identity.Name == "test1#outlook.com")
{
context.Response.Redirect("Home/Contact", true);
}
await next();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Note, change the redirect URL and MVC Route based on your Area
U can use action like this:
public IActionResult MyIndex()
{
string action = // get action for user
return RedirectToAction(action, "Home")
}
along with tag helper:
<a asp-controller="Home" asp-action="MyIndex">Go somewhere</a>

Laravel routes.php include file using Session

Not sure if this is possible, but here it goes.
What I am looking to do is include my "admin" routes as a separate file, only if the user is an admin (therefore a non admin will get a 404 error
routes.php
if( Session::get('user')->is_admin )
require_once('routes-admin.php');
if( Auth::check() )
require_once('routes-user.php');
Route::get('/', function() {
return view('home');
});
routes-admin.php
Route::get('admin', function() {
return view('admin-dashboard');
});
routes-user.php
Route::get('user', function() {
return view('user-dashboard');
});
What I am trying to do is avoid having the test repeated with every single Route
so if my user segment has 10 pages I currently need 30 lines of code dedicated to Auth::check() (the if, else and redirect if not), where I can instead have a single check on routes.php and the user will get a 404 if they don't belong
Is there a way to perform this check outside of the Route?
Perhaps you want to read documentation first?
Route::group(['middleware' => 'auth'], function()
{
Route::get('/', function()
{
// Uses Auth Middleware
});
Route::get('user/profile', function()
{
// Uses Auth Middleware
});
});
Above code does exactly what you need, is "person logged in?" let him go to page "whatever".
You can create middlewares (check if user is admin or basic user) yourself and apply on groups.
Example middleware
class BeforeMiddleware implements Middleware
{
public function handle($request, Closure $next)
{
// Perform action
return $next($request);
}
}
Do not get me wrong, just your approach is really not Laravel like. Try to see some open source projects done in L5 or even in L4. Try to use everything Taylor already done for you. Documentation is your firend here.
Following the response of #Kyslik for the middleware, you can "include" your own routes file in your RouteServiceProvider like the default routes file, the RouteServiceProvide is located in: app/Providers/RouteServiceProvider.php,
Find the section
require app_path('Http/routes.php');
and just replicate with the name of your routes file want to include

'auth' Middleware with Route::resource

How can I use middleware with resources?
Route::resource('myitem', ['middleware' => 'auth', 'uses' => 'App\\Controllers\\MyitemsController']);
Just followed https://laracasts.com/discuss/channels/general-discussion/struggling-with-routeresource-and-auth-middleware but unfortunately could not solve.
Getting error:
ErrorException (E_UNKNOWN)
Array to string conversion
Open: /vendor/laravel/framework/src/Illuminate/Routing/Router.php
protected function getResourceAction($resource, $controller, $method, $options)
{
$name = $this->getResourceName($resource, $method, $options);
return array('as' => $name, 'uses' => $controller.'#'.$method);
}
Using filter with resource was not working that why had to use Route::group
Route::group(array('before' => 'auth'), function()
{
Route::resource('myitem', 'App\\Controllers\\MyitemsController');
});
https://stackoverflow.com/a/17512478/540144
Middleware is a new feature of Laravel 5. In Laravel 4, filters where something similar. So instead of using the key middleware you should use before or after. Also, and that's where the error comes from, the second argument of Route::resource should be the controller name as string and the third one is an array of options:
Route::resource('myitem', 'App\\Controllers\\MyitemsController', ['before' => 'auth']);
Edit
Apparently before filters only work with resource routes when you wrap a group around it. See the OPs answer for an example...
I just came up against this and found the easiest way is to add the middleware straight to the controller.
I found my answer here:
http://laravel.com/docs/master/controllers
class MyitemsController extends Controller {
/**
* Instantiate a new MyitemsController instance.
*/
public function __construct()
{
$this->middleware('auth');
}
}
How to do this in Laravel 5. The Answer you have been waiting for.
Use middleware instead of before
Route::group(array('middleware' => 'auth'), function()
{
Route::resource('user', 'UserController',
['only' => ['edit']]);
}
To check if the route is setup, run:
php artisan route:list
which should show the following:
GET|HEAD | user/{user}/edit | user.edit | App\Http\Controllers\UserController#edit | auth
Note auth instead of guest
Better solution
Use middleware instead of before
Route::group(['middleware' => 'auth'], function(){
Route::resource('myitem', 'MyitemsController');
});
You can check if it's ok with:
php artisan route:list