Blazor Secure Api - api

I am developing an Application in Microsoft Blazor. I have secured all the UI Pages using a custom AuthenticationStateProvider class which searches for a cookie on the browser.
The by restricting the #Body on the MainLayout.razor every page is secured and not readable when the user is not autorized.
<div class="page">
<Sidebar />
<div class="main">
<Header />
<article class="content px-4">
<AuthorizeView>
<NotAuthorized>
<div class="row">
<div class="col-md-4">
<p>Please sign in to use the Platform...</p>
</div>
</div>
</NotAuthorized>
<Authorized>
#Body
</Authorized>
</AuthorizeView>
</article>
</div>
</div>
The issue is that the ./api endpoint is still accessible for not authorized users as the controllers are still active.
[Route("api/User")]
[ApiController]
public class Controller_User : ControllerBase
{
private readonly Interface_User _IUser;
public Controller_User(Interface_User iUser)
{
_IUser = iUser;
}
[HttpGet, Route("/api/user/view")]
public async Task<List<User>> GetUsers()
{
try { return await Task.FromResult(_IUser.GetUsers()); }
catch { throw; }
}
}
Any ideas how we can secure all ./api urls at once like the razor pages?

Example using inheritance to apply Authorization to controllers.
Two abstract controllers
[Authorize]
public abstract class AuthorizedController: Controller {}
[Authorize(Policy = "AdminOnly")]
public abstract class AdminOnlyAuthorizedController: Controller {}
And then some implementations
public sealed class WeatherForecastController: AuthorizedController {
//....
}
public sealed class WeatherLocationController: AuthorizedController {
//....
public class MyAdminController: AdminOnlyAuthorizedController {
//....
}

Related

How to access C# application from jQuery in Razor Pages?

Environment: ASP.NET Core 6.0, Razor Pages
Authentication:
The users log in, and their access token (Bearer jwt) is stored in Session storage.
The problem:
I want to display an array of objects that a request gives me. These objects have a part that has to be queried separately for each of them from the backend. For presentation purposes, I want to display them on the same page, but I do not want to query them before the page loads, because that is slow.
So the question is, how to access HttpClient (or the service that uses HttpClient and handles requests) from jQuery? My current idea is to pass the Bearer token to the partials, that way it can be accessed from them, and to go with an XMLHttpRequest. Are there any better solutions to populate these dropdowns on demand?
Index.cshtml
#page
#model IndexModel
#foreach (var part in Model.Parts)
{
<partial name="_PartPartial" model="new { PartData = part, Id = #Model.Id, Bearer = Bearer }" />
}
Index.cshtml.cs
public class IndexModel : PageModel
{
public List<PartModel> Parts;
public string Id;
public async Task<IActionResult> OnGetAsync(string Id)
{
// Query Parts from endpoint...
return Page();
}
}
_PartPartial.cshtml
#model dynamic
<div class="card">
<div class="card-header">
<button type="button" class="btn" data-bs-toggle="collapse" data-bs-target="#partContent_#Model.PartData.partId"
aria-expanded="false" aria-controls="partContent_#Model.PartData.partId" data-id="#Model.PartData.partId" onclick="queryInnerData(this);">
#Model.PartData.DisplayName
</button>
</div>
<div class="collapse" id="partContent_#Model.PartData.partId">
<div class="card card-body">
<div id="innerData_#Model.PartData.partId"></div>
</div>
</div>
</div>
<script type="text/javascript">
function queryInnerData(sender)
{
// This is the part where I am stuck. How do I access the Bearer
}
</script>
I have tried creating a page that does an HttpRequest and returns a JsonResult in its OnGet method. This works, but exposes the raw data to the outside world as well, so I would rather not go with this solution.

Changing attributes of HTML element in server-side code in Razor Pages

I want to be able to access and modify attributes of HTML elements of a page in my server side code (I am using ASP.NET Core Razor Pages 6.0).
For example: a .cshtml file, I have a simple element like this:
<div class="mb-3 mt-3">
<label asp-for="User.firstname" class="form-label">First Name:</label>
<input asp-for="User.firstname" class="form-control" placeholder="First Name">
</div>
How do I access & change attributes of the above <input> element inside the OnGet or OnPost server-side methods?
I need to do so as I want to add a class to that <input> element, or make it read-only (depending on certain conditions in my server code).
In older versions of .NET, I believe this was possible by giving an HTML element an ID, and writing runat="server". Then, one could access the element in the code-behind via its ID and change its attributes. How is this done now in Razor Pages?
Should I not be able to do the same because of the asp-for tag helper which I used inn my code above? But how?
Thank you for your help!
you can achieve sending Value to the server with
This at razor page:
<form method="post">
<div class="form-group">
<input name="title" class="form-control" placeholder="Type title here.." />
<button type="submit" class="btn btn-primary">Post</button>
</form>
This at Model Page
public async Task<IActionResult> OnPostAsync(string title)
{
//do your stuff
}
Put breakpoint at public async Taks and viola.
I believe this should do the trick. You can change it for yourself.
Here is a whole working demo you could follow:
Model
public class User
{
public string firstname { get; set; }
}
Page(.cshtml file)
#page
#model IndexModel
<form method="post">
<div class="mb-3 mt-3">
<label asp-for="User.firstname" class="form-label">First Name:</label>
<input asp-for="User.firstname" class="form-control" placeholder="First Name">
</div>
<input type="submit" value="Post"/>
</form>
PageModel(.cshtml.cs file)
1.For model binding of the element, one way is that you can use [BindProperty]:
public class IndexModel : PageModel
{
[BindProperty]
public User User { get; set; }
public void OnGet()
{
}
public void OnPost()
{
//do your stuff.....
}
}
2.The second way is that you can add parameters like below:
public class IndexModel : PageModel
{
public User User { get; set; }
public void OnGet()
{
}
public void OnPost(User User)
{
}
}

How to change style of an element in code behind .net Core

How can I change the classes/Style of a div in my controller? I tried using runat but it didnt work. here is an example
<div id="MainDiv" class="flex justify-between items-center">
<a>Done</a>
</div>
How can i add a bg-red-300 class to MainDiv if certain conditions apply and if not add a bg-green-300 class instead?
The first way,you could judge the data in client side like below:
#model Test
<div id="MainDiv" class="flex justify-between items-center #(Model.IsDone=="Yes"?"bg-red-300":"bg-green-300")">
Controller:
public IActionResult Index()
{
var model = new Test()
{
IsDone=="Yes"
};
return View(model);
}
The second way,you could use ViewData to store the class and judge in the server side:
Index.cshtml:
#{
var styleClass = ViewData["Style"];
}
<div id="MainDiv" class="flex justify-between items-center #styleClass">
<a>Done</a>
</div>
Controller:
public IActionResult Index()
{
if(YourCondition)
{
ViewData["Style"] = "bg-red-300";
}
else
{
ViewData["Style"] = "bg-green-300";
}
return View();
}
I will assume that you have a Model backing your view, with some C# property of a boolean type that will define if this field is valid, or not, let's call it Valid. Usually such validation is based on some more complex logic so I assume you have something like that.
You could edit the style inline, or replace whole blocks of HTML view depending on how much of the view you need to change based on this model value.
Both approaches are documented with example fiddle for you to eventually play with it.
I see you're using tailwindcss, so I have simply copied this style.
using System;
namespace ExampleApp
{
public class SampleViewModel
{
public bool Valid { get; set; }
}
}
Example Controller:
using System;
using System.Web.Mvc;
namespace ExampleApp
{
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
var model = new SampleViewModel();
model.Valid = false;
return View(model);
}
}
}
And example view:
#model ExampleApp.SampleViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Css based on Model</title>
<style type="text/css">
.bg-red-300 {
background-color: #feb2b2;
}
</style>
</head>
<body>
<div id="MainDiv" class="flex justify-between items-center">
<span>Done</span>
</div>
<!-- Whole block change -->
#if (Model.Valid)
{
<div id="MainDiv" class="flex justify-between items-center">
<span>Done</span>
</div>
}
else
{
<div id="MainDiv" class="flex justify-between items-center bg-red-300">
<span>Done</span>
</div>
}
<!-- inline style change -->
<div id="MainDiv2" class="flex justify-between items-center #(Model.Valid ? "" : " bg-red-300")">
<span>Done</span>
</div>
</body>
</html>
I have posted a simple .net fiddle for you to check live:
https://dotnetfiddle.net/h7JTR2

Why form in RCL(Razor Class Library) no working in asp.net core?

Here is my code in front-end:
#model Sample.Models.VistorModel
#using Microsoft.AspNetCore.Mvc.Localization
#inject IViewLocalizer Localizer
<form id="ContactForm" asp-action="Contact">
<div>
<h3>#Localizer["Name"]</h3>
<span asp-validation-for="Name"></span>
</div>
<input asp-for="Name" placeholder="#Localizer["NameHint"]" />
<div>
<h3>#Localizer["Phone"]</h3>
<span asp-validation-for="Phone"></span>
</div>
<input asp-for="Phone" placeholder="#Localizer["PhoneHint"]" type="tel" />
<button type="submit">#Localizer["Sumit"]</button>
</form>
Here is the model:
public class VistorModel
{
[Required(ErrorMessageResourceName = "NameError", ErrorMessageResourceType = typeof(Sample.Resources.Views.Contact.Contact))]
public string Name { get; set; }
[Required(ErrorMessageResourceName = "PhoneError", ErrorMessageResourceType = typeof(Sample.Resources.Views.Contact.Contact))]
[RegularExpression(#"((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)", ErrorMessageResourceName = "NotAPhoneNumber", ErrorMessageResourceType = typeof(Sample.Resources.Views.Contact.Contact))]
public string Phone { get; set; }
}
And here is the controller:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sample.Controllers
{
[Route("{culture}/[controller]")]
public class ContactController : Controller
{
[Route("Contact.html")]
public IActionResult Contact()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
[Route("Contact.html")]
public IActionResult Contact(Models.VistorModel Vistor)
{
if (ModelState.IsValid)
{
}
return View();
}
}
}
I add a breakpoint in the controller and found the public IActionResult Contact(Models.VistorModel Vistor) never be invoked while I clicked the button. It always invokes the public IActionResult Contact() only.
I made another test to migrate all the code above to a brand new asp.net Core MVC project and it works well.
What's wrong with this?
To Fei Han, here is the source html code in browser:
<form id="ContactForm" asp-action="Contact" method="post">
<div>
<h3>Name</h3>
<span asp-validation-for="Name"></span>
</div>
<input asp-for="Name" placeholder="Your name">
<div>
<h3>Phone</h3>
<span asp-validation-for="Phone"></span>
</div>
<input asp-for="Phone" placeholder="Your phone" type="tel">
<button type="submit">Sumit</button>
</form>
What's more, I render the RCL in asp.net core project like this:
#await Html.PartialAsync("/Views/Contact/Contact.cshtml")
the public IActionResult Contact(Models.VistorModel Vistor) never be invoked while I clicked the button. It always invokes the public IActionResult Contact()only.
Please try to set method="post" for your form tag, like below.
<form id="ContactForm" method="post" asp-action="Contact">
Update:
To make the Form tag helper etc available to view(s) in RCL, we can add following code in view page or Razor View Imports file.
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Blazor WASM LayoutComponentBase with #Body and more properties

My use case is I have the MainLayout.razor with this code
#inherits LayoutComponentBase
<header><nav ....></header>
<section><h1>Page Title</h1><section>
<main class="container">
<div class="row"><div class="col-12">#Body</div></div>
</main>
Now I want to set the page title from every #Body razor fragment (maybe by inheritance)
#page "/about"
<div>....</div>
#code {
Title = "About Title";
}
I want avoid to put <section> inside the #body fragment.
Also have the same problem with the title-element from head-element. What is best practices to do this (without js interop)?
There are a couple of ways to do that...
Using CascadingValue feature
Define a property in MainLayout to get the title from child components such as
the about component.
Add a CascadingValue component to MainLayout, and pass the MainLayout component
as the value of the Value attribute.
In the child component define a CascadingParameter property which stores the
MainLayout object, and assign a title to its Title property
Here's the full code:
MainLayout
<div class="main">
<div class="top-row px-4 auth">
<h1>#Title</h1>
<LoginDisplay />
About
</div>
<div class="content px-4">
<CascadingValue Value="this">
#Body
</CascadingValue>
</div>
</div>
#code
{
string title;
public string Title
{
get => title;
set
{
if(title != value)
{
title = value;
StateHasChanged();
}
}
}
}
About.razor
#page "/about"
<div>....</div>
#code {
[CascadingParameter]
public MainLayout MainLayout { get; set; }
protected override void OnInitialized()
{
MainLayout.Title = "About Title";
}
}
Create a service class that defines a Title property that can be set by
components into which the service is injected. This service class should also provide a way to pass the title supplied by child components to the MainLayout, which should refresh itself in order to display the provided title...
Hope this helps...