How to prevent user from accessing certain URL directly in ASP.Net MVC 5

别说谁变了你拦得住时间么 提交于 2019-12-08 11:03:35

问题


Ok, So I am learning ASP.Net MVC 5 by doing small projects. I am implementing forgot password functionality. Here is the flow:

  1. User clicks on forgets the password link.
  2. Redirects to page where User enters the email.
  3. Receives a token and redirects to a page to enter the token received
  4. Gets redirected to "password" and "confirm password" page

Now all these pages have their separate URL and pages should open in that order. But If I type the URL which is required for may be 3rd step (enter the token) or URL of 4th Step (enter the new password) in my browser link I can open the corresponding page. But I do not want that. If someone is not following steps 1 to 4 then they cannot directly open any out of sequence URL. How to achieve above functionality.

Note: If we add a [Authorize] attribute to our controller action then no matter which URL we access in browser we always get redirected to login page (provided not already logged in). Can I achieve something like above. So, if someone tries to open /VerifyToken Page directly then he should be redirected to page /SendEmailForReceiveingToken .

EDIT 1

Ok, Here is the thing. In order to identify the right person, I am using the token. But in order to check the token field in my Database I want to uniquely know the user. For that I am utilizing the email Id. So basically I query the DB with email ID to find the user and then check the token set in that row. But if someone directly goes to verify token, then I will not be able to know his email Id. As of now I am passing the email as hidden field among token page and resetpassword page

EDIT 2 So at 12:00 AM user got the token. But he did not go ahead with the "Reset Password". He comes after 2 mins and directly goes to /VerifyToken page and enters the token. So now I do not have access to the email id. How can I verify the token now. I do not want to query entire token column and match the corresponding row.


回答1:


There's nothing wrong with an arbitrary user opening for example page 3 where he is supposed to enter a valid token. If he doesn't have received such valid token before and you have proper validation of the token on the next step, then this user cannot do anything useful. You are over-complicating the design.

Just put proper validation on the step where the actual password reset happens - verify that a valid token has been entered. It doesn't matter the page from which this token has been submitted as soon as the token is valid.




回答2:


You are correct in thinking that you need email address in order to verify the token. However you do not need to establish a rigid flow for this purpose.

You can just insert email address to password reset url as a query parameter. Example url:

http://www.example.com/resetpassword/ZXhhbXBsZQ?email=example@example.com

Then you query tokens of the user with the designated email.

Or you can ask for user email at step 3 or 4. If you take a look at ASP.NET Identity based default project Visual Studio creates, that's what you'll see. Password form also asks the user to enter his email.

Or alternatively you can use a more advanced token, in which it is possible to embed information. For example it is possible to embed user principals into a JWT token. However, my personal opinion this is an overkill for password reset. One apparent downside is JWT tokens and thus your password reset URLs will be much longer.




回答3:


Assuming your tokens are actually unique, you don't actually need to know the email address / user name for the user. The token acts as a (temporary) unique ID for a user record, so you can just persist that token within the "enter your new password" view, and use that within your reset logic:

public bool UpdatePasswordForToken(string token, string newPassword)
{
    bool success = false;

    var user = Context.Users.SingleOrDefault(u => u.ResetToken.Equals(token, StringComparison.OrdinalIgnoreCase));
    if (user != null)
    {
        var password = Crypto.HashPassword(newPassword);
        if (!string.IsNullOrWhiteSpace(password))
        {
            user.Password = password;
            user.ResetToken = null;

            Context.SaveChanges();

            success = true;
        }
    }

    return success;
}

This assumes that you don't just log the user in when they complete the password reset. I redirect to the login page (with a success message). Even if someone managed to guess a valid reset token (which means the tokens aren't really unique), they would need to know which user name they just reset, in order to log in as the (now compromised) user.

If you're really set on a user only following your workflow, the obvious answer seems to be checking the Request.UrlReferrer value, and bouncing the user from the current action if it's not the action you wanted to proceed this action. UrlReferrer isn't bulletproof, though, so I would recommend just simplifying your workflow like I note above.



来源:https://stackoverflow.com/questions/43575329/how-to-prevent-user-from-accessing-certain-url-directly-in-asp-net-mvc-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!