Detect what Attributes are set on a controllers action during Application_AuthenticateRequest - asp.net

I get a call to Application_AuthenticateRequest which I use to perform some authentication logic. Something similar to:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (System.Web.HttpContext.Current.Request.IsAuthenticated)
{
....
}
}
That works generally fine, however in some cases my controller actions have the AllowAnonymous attribute attached, and I do not want the code to execute. The is no problem if the user is not logged in, however, if the user is logged in and they attempt to access one of these views, I run into an issue.
What I'm wondering is, if there is a way I can detect what attributes are set on my action in the Application_AuthenticateRequest call. Or if I could even detect if the current page requres authentication?
So far I haven't been able to figure this out, but it seems like it should be fairly simple. I'm wondering if someone could point out something that I'm missing?

This question is little old. But I came across to find an answer. I found a solution by using System.Web.HttpContext.Current.SkipAuthorization
This returns true if the action has [AllowAnonymous] attribute,
Else this returns false if the action has [Authorize] attribute.

Related

How to prevent/stop event bubbling/propagation on page load in asp.net

I would like to know if I can prevent the event bubbling / propagation on the page load based on condition like:
protected override void OnLoad(EventArgs e)
{
// If the user press F5 from the browser
if (IsRefresh)
{
// Here I want to stop propagation/bubbling the events like OnClick of a submit button but without using the button object (I want it generic)
}
else
{
base.OnLoad(e);
}
}
Is this possible?
Prevent the event bubbling has two difficulties - detect the F5 and stop the events - i would simply use the Post/Redirect/Get-pattern:
protected void Button1_Click(object sender, System.EventArgs e)
{
// do what you need to do
// now redirect to the same page,
// then a browser-refresh via F5 won't trigger this event again
Response.Redirect(Request.Url.PathAndQuery);
}
I did once in ASP.NET WebForms project when user press on F5 it'll do something other than refresh, I done this by use jQuery keypress even for the page and call e.preventDefault(); check this
Update:
$(document).ready(){function(){
this.keydown(e){
if (e.which == 116){
e.preventDefault();
window.location.href = "http://foo.com/?IsReferesh=1";
}
};
)};
You can use the QueryString to check if user press F5 and the reflection in Code Behind. If I missed something, then I didn't fully understand your question.
Regarding the specifics of your question, how about inverting it? Maybe add a Load event listener (say, in page Init) only if the condition is not met.
Another option might be doing something like:
this.Load -= MyPageLoadMethod;
You are likely looking at the event itself, not the OnLoad method. Eitherway, I think it is possible, see some options here How to remove all event handlers from a control
There is a big "BUT" though...
Like most people here, I think you are not solving the right problem. I'm sorry the same applies for Emad's solution I think.
Tim nailed it. This answer will try to explain this option more.
The pattern Post-Get-redirect is very popular and very standard. In most of our applications, submitting the same form more than once either by re-clicking the submit button before page loading or refreshing the browser causing another POST call is wrong, so, the practice of redirect after a non-AJAX form submission has become so standard.
Everything else you may try will be no more of a dirty workaround than a proper solution.
--
Now, comes the problem of providing feedback to the user. Ruby On Rails provides a nifty helper for this called Flash helper. It's a message you can set before redirecting (or even in the same page if there is no redirect) and the next time you display it, it'll destroy itself, the next time you call it, you get nothing. so, you display nothing.
ASP.NET MVC has something like this which is TempData. TempData can be stored in many places, by default in the Session, so, if you are redirecting from an MVC action, you can set something like TempData['Message'] , and read it in the next Controller. ASP.NET MVC will handle removing it after the redirect.
So, how about Webforms? There's nothing to prevent you from doing it too. It really isn't rocket science
You can check for URL Referrer whether it is an edit page or not and display message based on that.
You can store a message in Session before redirect, and check for it in every page load, if found, you display it and delete it from Session
If Session is disabled, you can use cookies. You can check the date of the cookie before sending, so that if the redirect never happened (use network dropped or whatever) and use came to the page later in the time he doesn't see an outdated message.
You can also store in Cache (with some key related to user of course, as Cache is application wide), You can then set the Cache expiration to some short period to avoid the problem explained in cookies option
You can also google for Rails Flash-like for ASP.NET Webforms to see what reusable components other people came up with. This result for example came in my search:
http://highoncoding.com/Articles/542_Creating_Rails_Like_Flash_Feature_in__NET_The_Flash_Control.aspx
Check NuGet also maybe there's something there. Again, it's not hard to build your own anyway.
Update:
Another simple approach might be to just redirect to the same URL, this'll cause a GET request and will not run any handler, pretty close to the original implementation of Post-Get-Redirect (yours will be Post-Post-Redirect maybe, kidding), and pretty safe as well.
Something like:
Response.Redirect(Request.RawUrl);
Update 2
Just as mentioned above, if you are running after page init, say in page Load, you can always emove events in a way similar to:
this.SubmitButton.Click -= SubmitButton_Click;
You get the idea...
That's useful if what you want is stop particular events, while the previous bits of the answer were assuming you are trying to stop most of the events.
http://gurustop.net
protected override void OnLoad(EventArgs e)
{
if (!IsPostBack)
{
if (Request.UrlReferrer != null)
if (Request.UrlReferrer.PathAndQuery == Request.RawUrl)
{
// Show Message
}
}
}
protected void Button1_Click(object sender, System.EventArgs e)
{
Response.Redirect(Request.Url.PathAndQuery);
}
Note:
if (Request.UrlReferrer.PathAndQuery == Request.RawUrl) // does not work with chrome
so you can replace it with
if (Request.UrlReferrer.AbsolutePath == Request.Url.AbsolutePath)
static string REFRESH_CHECK_GUID = "REFRESH_CHECK_GUID";
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState[REFRESH_CHECK_GUID] != null && !ViewState[REFRESH_CHECK_GUID].ToString().Equals(Session[REFRESH_CHECK_GUID].ToString()))
{
Response.Redirect("Login.Aspx");
}
Session[REFRESH_CHECK_GUID] = System.Guid.NewGuid().ToString();
ViewState[REFRESH_CHECK_GUID] = Session[REFRESH_CHECK_GUID];

Register before entering the main site

When someone visits my site and if there isn't any admin registered they should be redirected to that Adminregistration page.
Now this should ONLY happen when there isn't any admin registered whatsoever. So it should only happen when the database is fresh and empty without data.
I know I can put a check with a validationattribute on all controllers. But I find that a bit of a hack and well... The check should be completely removed when there is 1 registered anyway.
So is there another way to accomplish this?
If you have a base controller that all your controllers inherit from, you could put the "validationattribute" you mention on the base controller to trigger the validation on every request, if that is what you want.
Edit
You could store a global variable in web.config called say AdminIsRegistered that is set to false when the application is first shipped. Then you change that value programatically when the first admin registers like this and set it to true. Your custom attribute set on the base controller could then simply check that value on every request, as long as it is set to false, the attribute redirect the user to the registration action, otherwise it does nothing.
The best way to do this is with a global filter. You register it once in your application, and every action that executes will hit the filter first. All you have to do is add it to the global filter collection on Application_Start:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalFilters.Filters.Add(new AdminRequiredAttribute());
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}

Can I hook up to any forms authentication sign out event?

I would like to do som extra processing whenever a user is signed out from forms authentication.
According to this MSDN article
there is a
FormsAuthentication_OnAuthenticate
event but I need something like a
"FormsAuthentication_OnSignOut" (Which doesn't exist)
Any ideas?
/J
Keep the user signed in until they explicitly sign out - and when they click the logout link use something like the following:
private void OnLogOut (Object sender, EventArgs e)
{
FormsAuthentication.SignOut ();
//extra processing here
}
As far as I have been able to find out there are no way to make this hook.
You have to add any extra code to the place where you do the FormsAuthentication.Signout().
(Of course you could apply some AOP techniques but this was not relevant in my case)

FormsAuthentication.RedirectFromLoginPage – really strange and inconsistent results

I’m trying to figure out whether FormsAuthentication.RedirectFromLoginPage (called inside method M()), performs redirection the moment method M finishes its execution, or whether page first completes its lifecycle and only then redirects. But I can't figure it out due to inconsistent behavior:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
FormsAuthentication.RedirectFromLoginPage("someUser", false);
}
protected void LogOut_Click(object sender, EventArgs e)
{
FormsAuthentication.SignOut();
Session["LogOut"] = "LogOut_Click event handler";
}
protected void ClickMe_Click(object sender, EventArgs e)
{
Session["ClickMe"] = "ClickMe_click event handler";
}
If on postback user clicks LogOut button, then LogOut_Click() is executed prior to page being redirected. But if on postback user clicks on ClickMe button, the page is redirected before ClickMe_Click event handler is called.
Why is that? Thus, based on what criteria does FormsAuthentication.RedirectFromLoginPage decide which event handlers should be executed before the redirection?
thanx
EDIT:
The FormsAuthentication.RedirectFromLoginPage() method has nothing to do with logging out. It's used to manually log someone in and redirect them to the page they were originally trying to access.
I didn’t imply that it has anything to do with logging out
However, looking at your code samples, you could be asking why the code continues to execute in the LogOut_Click function even if the user is logged out.
No, I didn’t ask that either.
Now, it also occurs to me that you could be asking about FormsAuthentication.RedirectToLoginPage instead of RedirectFromLoginPage.
I didn’t ask that either
What I’m asking is why when FormsAuthentication.RedirectFromLoginPage is called inside Page_Load, if postback was caused by LogOut button, then LogOut_Click() method does run before page is redirected, but if ClickMe button causes the postback, ClickMe_Click() event handler doesn’t have a chance to run before a page is redirected. In other words, I would expect that ClickMe_Click would also have a chance to run before page was redirected ( assuming ClickMe button caused a postback )
Okay,
From what I can tell from trying out this scenario is this.
The redirect doesn't stop the page from finishing it's lifecycle.
Microsoft should have added another overload for RedirectFromLoginPage that included 'endResponse' like it did for Response.Redirect. Unfortunately they didn't. Being that the Page_Load runs before any of the postback events, and that you are calling the RedirecFromLoginPage before the event fires you will need to stop the current page from finishing it's currently processing life cycle.
It's far from elegant, however putting a
FormsAuthentication.RedirecFromLoginPage("someUser", false);
Response.End();
after your RedirectFromLoginPage to discontinue the current page lifecycle and therefore stopping any other events firing and you should get the action you are looking for. At least I hope. This will however cause a 'System.Threading.ThreadAbortException' just like if you were to pass true in to Response.Redirect as the 'endResponse' parameter.
Hope this helps.
Edit - new answer
OK. I see that I did mis-read the question completely. Sorry.
I'm posting this new answer, but I'm afraid I'm still not going to answer the "why" for you. I do know this.
According to the remarks section documentation for the Response.Redirect method, it says
Redirect calls End which raises a
ThreadAbortException exception upon
completion.
However, in the documentation for FormsAuthentication.RedirectFromLoginPage() there is no similar remark. IN know that no documentation is perfect, but Microsoft does a very good job with the MSDN library, so I can only assume that the reason for this is that they chose not t call End in the FormsAuthentication.RedirectFromLoginPage() method for some reason. Perhaps an oversight?
At any rate, to me, this seems like a mistake. You'd think that both methods would act the same, since both are redirect methods, which of course, is not an answer to your question. I guess now I'm just still in the same boat as you, wondering why this is.
I'm sure you've already figured this out, but I believe you could get around this by just using a normal Response.Redirect method and not using FormsAuthentication.RedirectToLoginPage. In all honesty, I've never seen the RedirectToLoginPage used before, so I'm curious as to why you would use it instead of Response.Redirect.
End Edit - original answer below
I'm not sure I'm reading this properly.
The FormsAuthentication.RedirectFromLoginPage() method has nothing to do with logging out. It's used to manually log someone in and redirect them to the page they were originally trying to access.
However, looking at your code samples, you could be asking why the code continues to execute in the LogOut_Click function even if the user is logged out. That's pretty simple to answer. The security permissions are checked when the Application_AuthenticateRequest event fires, which is prior to the event handling code.
So even though you've logged the user out, the user was authenticated at the time the credentials were checked. The runtime won't check the credentials again as long as the user is in that page.
I was trying to think of a real-world comparison and came up with this. In our company we have a swipe card that we have to use to get in the building and in certain sensitive areas. If I'm employed at the beginning of the day, and get fired later in the day, I'm still in the building. I can clean out my desk, etc. So I can still do things inside the building as long as I haven't left it yet.
That applies to your code as well... The user is already authenticated and in the page execution life cycle, so the code is allowed to continue.
Whether this SHOULD be this way is open for debate. Microsoft could have coded it so that calling FormsAuthentication.SignOut() also optionally terminates the processing similar to Response.Redirect, but apparently based on your code sample they didn't. Instead, calling SignOut() only removes the authentication cookie.
http://msdn.microsoft.com/en-us/library/system.web.security.formsauthentication.signout.aspx
Now, it also occurs to me that you could be asking about FormsAuthentication.RedirectToLoginPage instead of RedirectFromLoginPage. However, you don't show RedirectToLoginPage in your code or any other part of your question. If you want to log people out and redirect to the loin page immediately, you need to call FormsAuthentication.SignOut() followed by FormsAuthentication.RedirectToLoginPage() as shown in the link I posted above.

Asp.Net call function from a different *.aspx.cs page

If I have a button inside one page for example "main.aspx". And upon being clicked I want the clicked method in "main.aspx.cs" to call a function from a different *.aspx.cs page but also redirect to that *.aspx page...is that possible?
A more concrete example of what you're trying to do would be useful. Otherwise you'll get all sorts of answers, many of which will be off the mark.
You should put common code in the App_Code folder. You should also not have any business logic inside a forms code-behind.
The fact that you need one page to call a method in another page indicates that you haven't done this. Pages are for displaying and interpreting actions, but they should not hold any of the business logic.
e.g. a lame example of a shopping cart.
ProductView.aspx - calls Cart.AddToCart(Product p)
CartView.aspx - displays all items in the cart, and the user
can update or remove items.
- calls Cart.RemoveItem(int cartIndex)
- calls Cart.UpdateItem(int cartIndex, int newItemCount)
Cart itself doesn't belong in either CartView.aspx or ProductView.aspx. It instead belongs in ~/App_Code/Cart.cs
So your solution could look something like
/ (root of your web folder)
Product/
ProductView.aspx
ProductView.aspx.cs
Cart/
CartView.aspx
CartView.aspx.cs
App_Code/
Cart.cs
Product.cs
Also, to add the App_Code folder if it's not already there, right-click the web project and select Add ASP.NET folder and choose App_Code
You need to understand the ASP.NET Page lifecycle and you'll see why this is not Kosher. If you really need to call a method from multiple pages, it sounds like a good candidate for some external class/object.
Alternately, instead of using a querystring parameter, you can set a Session flag and then redirect to this new page. Then clear the session flag when you call that page's method.
In a very basic way, for Main.aspx to go to Other.aspx and to pass some small amount of data on the querystring to indicate an action.
Main.aspx
protected void OnSomeButtonClicked(object sender, EventArgs e)
{
if( someCondition )
{
Response.Redirect("~/Other.aspx?action=runAway");
}
}
in Other.aspx
protected void Page_Load(object sender, EventArgs e)
{
if( !IsPostBack )
{
if( "runAway".Equals(Request.QueryString["action"] )
{
RunAway();
}
}
}
You should also read up on Server.Transfer versus Response.Redirect. Which one to use is situation dependent.
Also note that QueryString parameters can be altered easily by the user, so always verify them and never trust the user.
Why don't you just redirect with a querystring parameter and then execute the function on the destination page?
Instantiate an object from your other page class and call the method.
protected Button1_Clicked(Sender s, Eventargs e){
MyNamespace.Page_Other po = new MyNamespace.Page_Other();
po.Method1();
Response.Redirect("~/page_other.aspx");
}

Resources