GetPdfBytesFromUrl sent from within controller still needs authentication - asp.net-mvc-4

I am using EVOPdf converter in my MVC4 project.
I am using the method pdfConverter.GetPdfBytesFromUrl to hit another controller action to return the rendered HTML and have that get converted into a PDF.
My problem is that I now have an [Authorize] attribute on the controller, now that same method only renders a log-in page.
Since I'm requesting the URL from within the same controller (but a different actionresult), is there any way to pass authentication?
string myOwnAddress = System.Configuration.ConfigurationManager.AppSettings["local-address"];
//THIS WILL NEED THE PARAMETERS SENT VIA THE GET URL
byte[] pdfBytes =
pdfConverter.GetPdfBytesFromUrl(myOwnAddress + "/ClinicianReportPDFRendered?PID=" + PID);

Unless somebody can come up with a better solution, I'm going to create a unique key in the requesting action to be passed/used one time and authenticate using that code in the other action.
The only downside is I'll have to take off the blanket [Authorize] on the top of the controller and apply it individually to each action result.

Related

How to prevent the flashing of content in a prerendered Blazor WebAssembly app?

The following code snippet can illustrate the issue present in Blazor applications which are rendered on the server side:
App.Client/Pages/Test.razor
#page "/test"
<p>#text</p>
#code
{
private string text;
protected override async Task OnInitializedAsync()
{
await Task.Delay(1000); // wait 1000 milliseconds
text = "foo";
}
}
When the component is first initailized on the server, the text variable is set to foo and a HTML document containing the string is sent over to the client. However, the client Blazor app isn't aware of the value that the server has assigned to the variable, which becomes null again. OnInitializedAsync is called again on the client and text is set back to foo, but only after a one second period during which there's nothing on the screen - a situation server-side rendering aims to avoid in the first place.
Do you know of any way to send components already populated with data?
Ok -- just being a bit picky -- this is a Blazor page....it isn't a component.
Yes, the pre-render they use isn't great, but assuming you're using Blazor for a SPA it should only happen once. Be careful to avoid a hard reload if you use the Microsoft.AspNetCore.Components.NavigationManager NavigateTo method. A hard re-load triggers pre-rendering because you refresh the SPA.
To avoid the whiplash, you want to avoid needing 1 second to load the text value. So you could use a singleton controller and inject it into the page. On the pre-render pass the value isn't yet known so we need 1 second to load it. Then on the client side pass the data could be accessed via the controller immediately.
Granted this isn't perfect if there is a ton of data to display. But in cases like that I generally show a 'loading' spinner and it gives the customer a feeling of controlled motion.

How to do a listener on every page load

I'm trying to limit the session access to a Struts application so the users will only be able to use 1 tab at the time. To do this, I have to create an ID everytime a new page is loaded and assign that ID to the user's session. By doing so, if the user uses a page with a different ID than the one registered in his session, the action will be rejected.
How can I do a listener on every page load? Which interface should I use?
Or do you have any other idea of how I could manage multiple tabs?
I'm Using Struts 1 and Java 4.
You could use Spring MVC Interceptors and override the preHandle method.
Returning false inside should cancel your request for not allowed additional tabs.
You can use an interceptor to do this. You will need to define it on your interceptor stack in your struts.xml and code the interceptor to check the JEE role information provided by your web application server. The interceptor can be coded to give a redirect result on the other tab if there was recently an action called however you will probably need to coordinate it via JS generated ids and AJAX.
https://struts.apache.org/docs/interceptors.html

Understanding ASP.net mvc4 code

public ActionResult Index()
{
return RedirectToAction("Index", "Login");
}
What does this code do? Index and login are views here?
This tells MVC to redirect to specified action instead of rendering HTML. In this case, browser receives the redirect notification and make a new request for the specified action. This acts like as Response.Redirect() in Asp.Net WebForm.
Moreover, RedirectToAction construct a redirect url to a specific action/controller in your application and use the route table to generate the correct URL.
For more about this look https://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction(v=vs.118).aspx

Simple lack of understanding - MVC Routing

I want to call a method in the controller. To do this, assuming default routing, I have to have a view that matches the controller I'm calling.
So if I have a contoller action
public ActionResult Edit(booking booking)
then I must have a view called Edit.
Is that right?
What I want to do is call any action in my controller from a given page without there being a view of the same name.
So if I'm on the Edit page, I should be able to call an action named createproduct, without there being a createproduct view.
You don't need to have a view for every controller action. You can just call an action by calling the correct URL, that's one of the advantages of MVC and routing. Routes don't have to represent a physical location. You should be able to do the following /Controller/Edit/booking
A controller action doesn't have to return a View. You tend to see the action method return View(), which renders a view with the same name as the action method by default. But you can return View("SomeOtherViewName"). You can also return various other results, such as FileResult (returns a file), HttpStatusCodeResult (returns an HTTP response code with no content), JsonResult (returns Json), Content (returns some string) etc. The Controller class has methods to help return some of these result types: File, Json, Content.

How do I simply set the ModelStateError from the HandleUnauthorizedRequest method?

So what is happening is that I have a condition within my override of the HandleUnauthorizedRequest method in my custom authorize attribute. Up to this point, I've been throwing a 403 which gets picked up and redirects to a custom error page. Well now, that's not really what I want. What I actually want is to show the same login page but add a message to the validation summary "You do not have access to this resource.", that way it's a bit more user friendly. It'll indicate that your creds were good, but you don't belong here.
I thought something like this would work:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// passed authentication, failed authorization
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Controller.ViewData.ModelState.AddModelError("", "Not Authorized");
return;
}
base.HandleUnauthorizedRequest(filterContext);
}
But this isn't working. What's happening is that the login page simply reloads. So this makes me feel like I'm close, but I need that model error to show up.
Any ideas?
UPDATE:
It would seem that the Controller that I'm adding an error to here is actually controller of whichever action had the attribute that led to here. I need to somehow add the error to the login controller. Not sure if that's even possible.
You are calling the base method here:
base.HandleUnauthorizedRequest(filterContext);
If you are using Forms Authentication this base method simply redirects you to the login page. And a redirect means a new HTTP request from the client. The current context and whatever you stored in it is lost. Well, to be more precise, the base method is returning a 401 HTTP status code which is then intercepted by the FormsAuthenticationModule which redirects to the login page defined in your web.config. But this implementation details is not important.
What you could do is perform the redirect yourself to the login page instead of leaving it to the base method. You could do this by setting the filterContext.Result property to a RedirectToRouteResult instance. In this case you could pass the error message as a query string parameter.
UPDATE:
According to your updated question it seems that you are calling return; after setting the ModelState value and not calling the base method and thus no redirect will happen to the login url. You could in this case return some error view by setting the filterContext.Result to an instance of a ViewResult in which view you could use the value you stored in the ModelState.