Blazor Navigation Manager / Authentication - authentication

I am using Blazor Authentication and I scaffolded the Logon Page. I wish to redirect on the Layout page to it when the user is not authenticated, but onfortunately it does not work.
Here is my code:
[Inject] private NavigationManager nav { get; set; }
protected override async Task OnInitializedAsync()
{
var authState = await auth.GetAuthenticationStateAsync();
var user = authState.User;
if (!user.Identity.IsAuthenticated)
{
nav.NavigateTo("/Identity/Account/Login");
}
}
What is actually happening is that Blazor think the page does not exist and renders the NotFound: <p>Sorry, there's nothing at this address.</p>.
That said; without doing anything else, when I refresh the page it actually opens the login page. This does not make sense to me.
Can anyone kindly help me to understand what is happening here.
Regards,
Chris

You should use the authorize page attribute. If you add it to the page, the blazor framework will redirect to the login page.
Is it a Blazor WASM app?

Related

Why OnValidatePrincipal is not called when navigating in Blazor pages and how to fix it

I have cookie authentication & OpenId setup to handle the OnValidatePrincipal:
.AddCookie(Constants.Cookies, options =>
{
options.Events.OnValidatePrincipal = ValidatePrincipalAsync;
}
static async Task ValidateAsync(CookieValidatePrincipalContext context)
{
// context.Request.Path
}
Inspecting the request path in the handler, I see it's is called for Request.Path with these paths: /, /_blazor/initializers, /_blazor/negotiate, /_blazor.
The handler is also called if navigate to any Razor server page (Pages/Test.cshtml).
But when I navigate in the Blazor app to different Blazor pages, the handler is not called.
Why isn't it called for Blazor pages too? Is it because Blazor server works with web sockets?
But isn't a problem that the validator is not called when navigating through the Blazor pages ? How to change so it's called for Blazor pages too?

ASP.NET Core 2 - How to remove scaffolded routes?

ASP.NET Core 2.x includes some pre-made scaffolded routes, like the login page, settings, etc. I am working on something that only has OAuth login buttons, and no settings. This means that I don't want users to be able to register with an email, and I don't want any settings pages.
I can remove the link to things like the Settings page , however the routes still exist and can be accessed by typing them in. How do I disable these routes so they are completely inaccessible?
Basically everything under the /Identity/Account/* route, except for the login page should not be available.
What you're referring to is the default Identity UI. It's included whenever you register Identity with services.AddDefaultIdentity or explicitly call AddDefaultUI when registering via the other IServiceCollection extensions (AddIdentity/AddIdentityCore). You cannot pick or choose what will or will not be included in the default UI, so if you don't want a part of it, then you cannot use it at all. Therefore, change the services.AddDefaultIdentity line to services.AddIdentity instead.
Once that's complete, you can use the Identity scaffold to include certain parts of the default UI in your application. Right click on your project and choose Add > New Scaffolded Item.... Then pick Identity on the left, and OK to use the only Identity scaffold available. On the resulting window, you can check the pages you want to include, and then click OK again.
For disabling the specific route for Razor Page, you could try IAsyncPageFilter.
public class DisableIdentityAsyncPageFilter : IAsyncPageFilter
{
public DisableIdentityAsyncPageFilter()
{
}
public async Task OnPageHandlerSelectionAsync(
PageHandlerSelectedContext context)
{
await Task.CompletedTask;
}
public async Task OnPageHandlerExecutionAsync(
PageHandlerExecutingContext context,
PageHandlerExecutionDelegate next)
{
if (context.HttpContext.Request.Path.StartsWithSegments("/Identity") &&
!context.HttpContext.Request.Path.StartsWithSegments("/Identity/Account/Login"))
{
context.Result = new StatusCodeResult(404);
}
else
{
await next.Invoke();
}
}
}
And then configure in Startup.cs
services.AddMvc(options => {
options.Filters.Add(typeof(DisableIdentityAsyncPageFilter));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

CakePHP Auth keeps redirecting me

Hi I have loaded the auth component and included the following;
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow('register', 'verify');
}
If I navigate to register it works correctly, however, if I go to verify it redirects me to login?
Any ideas?

Authenticating in Play without using routes

I've followed this tutorial for authentication and it works:
http://www.playframework.com/documentation/2.2.x/JavaGuide4
But I was wondering if there was another way to do it so that the user can't just go to myapp.com/login and get the login screen even if they're already logged in. Is there a way to do this so I can go to the login screen but still have myapp.com as the route?
This is easy. Just have the controller method for route "/" display the login page instead of your landing page when the user is not logged in.
Say / routes to Application.index() and it has a function isLoggedIn() to check login status, you could do something like this:
public static index() {
if (isLoggedIn()) {
return ok (index.render());
}
else {
return ok (login.render());
}
}

Refresh MVC view after logging in using Angular

Working with the Breeze Angular SPA template found here, http://www.breezejs.com/samples/breezeangular-template, I'm trying to update a menu that changes after user authenticates.
My example is slightly different from the default template in that I've moved the Login and Register views into modal windows. When the modal closes after a successful login, the menu, which is in the MVC View (and not the Angular View) does not update as a complete page refresh does not occur.
In the SPA template, authentication is required before entering the SPA, then a hard redirect/refresh occurs and the SPA is loaded. In my case, you could be browsing views/pages in the SPA before authenticating.
MVC View Code Snippet (Views/Home/Index.cshtml)
...
<li>
#if (#User.Identity.IsAuthenticated)
{
User Logged In: #User.Identity.Name
}
else
{
User Logged In: Annon
}
</li></ul>
<div ng-app="app">
<div ng-view></div>
</div>
....
I have working the root redirect, after login, the page hard refreshes if json.redirect is set to '/'. However, if its set to the current page, i.e. '#/about', Angular handles the routing and therefore no hard refresh occurs, thus the menu is not updated.
Ajax Login Code Snippet (App/ajaxlogin.js)
... part of login/register function
if (json.success) {
window.location = json.redirect || location.href;
} else if (json.errors) {
displayErrors($form, json.errors);
}
...
Is this possible to do using my current setup? Or do I need to move the menu somewhere inside the SPA and use Angular to determine what menu to show? If the latter, direction in how to best do this? I'm new to both Angular and Breeze.
The TempHire sample in Breeze has a really good way of handling authentication for a SPA (in my opinion at least!) Granted this is using Durandal so you will need to adapt it to Angular, but they are both frameworks doing the same basic principles so good luck! -
Basically, the Controller action has an annotation [Authorize] on the action that the prepare method is calling on the entitymanagerprovider. If a 401 is returned (not authorized) the SPA takes the bootPublic path and only exposes a login route to the user. When the login is successful, the login method tells the window to reload everything, at which time the authorization passes, and the bootPrivate method is called -
shell.js (Durandal, but should be adaptable)
//#region Internal Methods
function activate() {
return entitymanagerprovider
.prepare()
.then(bootPrivate)
.fail(function (e) {
if (e.status === 401) {
return bootPublic();
} else {
shell.handleError(e);
return false;
}
});
}
function bootPrivate() {
router.mapNav('home');
router.mapNav('resourcemgt', 'viewmodels/resourcemgt', 'Resource Management');
//router.mapRoute('resourcemgt/:id', 'viewmodels/resourcemgt', 'Resource Management', false);
log('TempHire Loaded!', null, true);
return router.activate('home');
}
function bootPublic() {
router.mapNav('login');
return router.activate('login');
}
login.js -
function loginUser() {
if (!self.isValid()) return Q.resolve(false);
return account.loginUser(self.username(), self.password())
.then(function() {
window.location = '/';
return true;
})
.fail(self.handleError);
}
The account.loginUser function is basically just an ajax call that passes credentials to the account controller and returns a success or failure. On success you can see the callback is fired for window.location = '/' which does a full reload. On failure simply show an alert or something.