Laravel routes.php include file using Session - authentication

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

Related

How to protect multiple routes from unauthorized access in Next.js using next-auth

I am using Next.js and I have a folder learning inside my pages folder. Now, this learning folder has about 10 pages.
All these pages need to redirect to the index page if the user is not logged in. The following code does the job, but is there any other way to protect multiple pages, so that I don't need to add this same code again and again to all the pages ?
export async function getServerSideProps(context) {
//redirect to index page if not logged in
const session = await unstable_getServerSession(context.req, context.res, authOptions);
if (!session) {
return {
redirect: {
destination: '/',
permanent: false
}
}
}
}
I believe you are confused between protecting pages and protecting API ROUTES.
If you simply want to protect pages, you can indeed use middleware
However, if you wish to protect API Routes (e.g prevent a user from deleting data using your API endpoint and postman), I believe you need to use this unstable_getServerSession
Except creating reusable function, it's true that I didn't find anywhere in the doc how to set it for multiple paths in one folder only...
you can use middleware. docs: https://next-auth.js.org/configuration/nextjs#middleware
Create a middleware.ts (or .js) file at the root or in the src directory (same level as your pages).
If you only want to secure certain pages, export a config object with a matcher:
export { default } from "next-auth/middleware"
// otherwise your app would require authentication for all
export const config = { matcher: ["/dashboard"] }
Now you will still be able to visit every page, but only /dashboard
will require authentication.
If a user is not logged in, the default behavior is to redirect them
to the sign-in page.
that example is from the docs. You can also write a custom middleware
import { NextResponse } from "next/server";
export function middleware(req) {
const sessionCookie = req.cookies.get("session");
}
// you could add more if logic for other pages
if (req.nextUrl.pathname.startsWith("/admin ")) {
if (!sessionCookie) {
return NextResponse.redirect("/home");
}
}

Reevaluate Nuxt.js middleware without a route change

I'm wondering if it's possible to essentially "reevaluate" the middleware conditions without actually changing the current route.
The middleware's purpose is to prevent non-logged-in users from accessing the "dashboard".
My issue is, a user could become logged in or logged out without necessarily changing route but they wouldn't be redirected until they try and change pages.
I have a VueX action that triggers when the user's auth state changes but this (from what I can see), can't access the redirect or route variables.
// /mixins/auth.js
const reevaluateAuthStatus = (store, redirect, route) => {
console.log(route)
const redirectPolicy = route.meta.map((meta) => {
if (meta.auth && typeof meta.auth.redirectPolicy !== 'undefined') { return meta.auth.redirectPolicy[0] }
return []
})
const user = store.getters['auth/getUser']
if (redirectPolicy.includes('LOGGEDOUT')) {
if (user) {
return redirect('/dashboard')
}
} else if (redirectPolicy.includes('LOGGEDIN')) {
if (!user) {
return redirect('/login')
}
}
}
module.exports = {
reevaluateAuthStatus
}
// /middleware/auth.js
import { reevaluateAuthStatus } from '../mixins/auth'
export default function ({ store, redirect, route }) {
reevaluateAuthStatus(store, redirect, route)
}
Appreciate any help on this :)
You cannot re-evaluate a middleware AFAIK because it's mainly this (as stated in the documentation)
middlewares will be called [...] on the client-side when navigating to further routes
2 clean ways you can still achieve this IMO:
use some websockets, either with socket.io or something similar like Apollo Subscriptions, to have your UI taking into account the new changes
export your middleware logic to some kind of call, that you could trigger again by calling the $fetch hook again or any other data-related fetching hook in Nuxt
Some more ugly solutions would probably be:
making an internal setInterval and check if the actual state is still valid every 5s or so
move to the same page you are actually on with something like this.$router.go(0) as somehow explained in the Vue router documentation
Still, most of the cases I don't think that this one may be a big issue if the user is logged out, because he will just be redirected once he tries something.
As if the user becomes logged-in, I'm not even sure on which case this one can happen if he is not doing something pro-active on your SPA.
I don't know if it's relevant or not, but I solved a similar problem this way:
I have a global middleware to check the auth status. It's a function that receives Context as a parameter.
I have a plugin that injects itself into context (e.g. $middleware).
The middleware function is imported here.
In this plugin I define a method that calls this middleware passing the context (since the Plugin has Context as parameter as well): ctx.$middleware.triggerMiddleware = () => middleware(ctx);
Now the middleware triggers on every route change as intended, but I can also call this.$middleware.triggerMiddleware() everywhere I want.

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:

Exclude a specific path from Express' all()

I'm using the following to check for privileges on every request to my server:
app.all('*',users.authCheck);
However, i wish to disable this for one specific request, namely the login route:
app.post('/users/login', users.login);
I know that i could move all my routes into another directory and change to app.all('foobar/*',users.authCheck);
However, i would rather like to exclude one route.
Is this possible?
You could simply add a if to your route:
// Somewhere in your app
users.authCheck = function(req, res, next) {
if (req.url === '/users/login') {
return;
}
};
That's not the best solution, however will help you for now.

Check each node.js request for authentication credentials

I'm using node.js with Express and connect-auth to authenticate users.
This is the verification when requesting /index:
if(req.isAuthenticated()) {
res.redirect('/dashboard');
} else {
res.render('index', { layout: 'nonav' });
}
However, after logging out and going back to f.e. '/dashboard', I can see the dashboard.
How can I put the authentication check to every request to make sure there's a valid user at all times?
Update
I don't have any problems with the authentication, everything works fine! I need a solution which checks every route/request if there's a valid user, without putting a function or if-statement in the route-implementation, as the whole App needs a valid user anyway. The Express-Authentication-Example uses "restrict" in the route-definition, which is close, but with many routes it can easily be forgotten.
app.all('*',function(req,res,next){
if(req.isAuthenticated()){
next();
}else{
next(new Error(401)); // 401 Not Authorized
}
});
// NOTE: depending on your version of express,
// you may need to use app.error here, rather
// than app.use.
app.use(function(err,req,res,next){
// Just basic, should be filled out to next()
// or respond on all possible code paths
if(err instanceof Error){
if(err.message === '401'){
res.render('error401');
}
}
});
If you define the all route before routes which require authentication and after routes which do not (such as the home page, login, etc) then it should only affect the routes that need it. Alternatively you could use a RegExp instead of '*', which would include a subpath or list of paths that require authentication.
Another option would be to create a function to include in each route that requires auth:
function IsAuthenticated(req,res,next){
if(req.isAuthenticated()){
next();
}else{
next(new Error(401));
}
}
app.get('/login',function(req,res,next){
res.render('login');
});
app.get('/dashboard',IsAuthenticated,function(req,res,next){
res.render('dashboard');
});
app.get('/settings',IsAuthenticated,function(req,res,next){
res.render('settings');
});
You can use sessions mechanism provided by connect. Put this code in app.configure() to enable it:
app.use(express.cookieParser());
app.use(express.session({
secret: 'some string used for calculating hash'
}));
After that, you′ll be able to use req.session object (different for each request) to store your authentication data (or anything else). So, your example code will look something like this:
if (req.session && req.session.authorized) {
res.redirect('/dashboard');
}
else {
res.render('index', {layout: 'nonav'});
}
And authentication will look like this:
req.session.authorized = checkPassword(login, passw);
Logout:
req.session.destroy();
More info can be found here.
Another way is to app.use a middleware function. (Example in CoffeeScript.)
# middleware
authKick = (req, res, next) ->
if not do req.isAuthenticated then return res.redirect '/login'
return do next
# apply
app.use authKick
This will work on each request without having to touch the routes.