एंटी जालसाजी टोकन उपयोगकर्ता के लिए है "" लेकिन वर्तमान उपयोगकर्ता "उपयोगकर्ता नाम" है


130

मैं एक सिंगल पेज एप्लिकेशन बना रहा हूं और एंटी-फर्जी टोकन के साथ एक समस्या का सामना कर रहा हूं।

मुझे पता है कि समस्या क्यों होती है मुझे नहीं पता कि इसे कैसे ठीक किया जाए।

निम्न होने पर मुझे त्रुटि मिलती है:

  1. गैर-लॉग-इन उपयोगकर्ता एक संवाद लोड करता है (उत्पन्न विरोधी जालसाजी टोकन के साथ)
  2. उपयोगकर्ता संवाद बंद कर देता है
  3. उपयोगकर्ता लॉग इन करता है
  4. उपयोगकर्ता एक ही संवाद खोलता है
  5. उपयोगकर्ता संवाद में फ़ॉर्म सबमिट करता है

एंटी जालसाज़ी टोकन उपयोगकर्ता के लिए है "" लेकिन वर्तमान उपयोगकर्ता "उपयोगकर्ता नाम" है

ऐसा होने का कारण यह है कि मेरा आवेदन 100% एकल-पृष्ठ है, और जब कोई उपयोगकर्ता सफलतापूर्वक अजाक्स पोस्ट के माध्यम से लॉग इन करता है /Account/JsonLogin, तो मैं सर्वर से वापस लौटे "प्रमाणित विचारों" के साथ वर्तमान दृश्यों को बंद कर देता हूं लेकिन फिर से लोड नहीं करता हूं पृष्ठ।

मुझे पता है कि यह कारण है क्योंकि अगर मैं चरण 3 और 4 के बीच का पृष्ठ पुनः लोड करता हूं, तो कोई त्रुटि नहीं है।

तो ऐसा लगता है कि @Html.AntiForgeryToken()लोड किए गए फॉर्म में अभी भी पुराने उपयोगकर्ता के लिए एक टोकन वापस आ जाता है, जब तक कि पेज पुनः लोड नहीं किया जाता है।

मैं @Html.AntiForgeryToken()नए, प्रमाणित उपयोगकर्ता के लिए टोकन वापस करने के लिए कैसे बदल सकता हूं ?

जब तक कहा जाता है, तब तक हर GenericalPrincipalएक रिवाज के साथ एक नया इंजेक्शन लगाता हूं , वास्तव में प्रॉपर्टी के साथ मेरी कस्टम आइडेंटिटी सही पर सेट होती है और फिर भी पुराने उपयोगकर्ता के लिए एक टोकन रेंडर करने के लिए लगता है जब तक कि मैं पेज लोड नहीं करता।IIdentityApplication_AuthenticateRequest@Html.AntiForgeryToken()HttpContext.Current.User.IdentityIsAuthenticated@Html.AntiForgeryToken


क्या आप वास्तव में यह सत्यापित कर सकते हैं कि @ Html.AntiForgeryToken कोड को पुनः लोड किए बिना कहा जा रहा है?
काइल सी

यह निश्चित रूप से है, मैं HttpContext.Current.User ऑब्जेक्ट का निरीक्षण करने के लिए वहां विराम कर सकता हूं जैसे कि मैंने उल्लेख किया है
संसद

2
कृपया इसे देखें: stackoverflow.com/a/19471680/193634
Rosdi Kasim

@ संवेदनशीलता आप नीचे दिए गए उत्तर में बता सकते हैं कि आप किस विकल्प के लिए गए थे।
सिद्धार्थ पांडे

मेरा मानना ​​है कि अगर मैंने सही तरीके से याद किया तो मैंने एक पूर्ण पुनः लोड के साथ जाने के लिए एक अपवाद बनाया। लेकिन मैं एक नई परियोजना में बहुत जल्द इस मुद्दे का सामना करने की उम्मीद करता हूं। अगर मैं बेहतर काम करने के विकल्प के साथ चुनाव करूंगा तो पोस्ट वापस कर दूंगा।
संसद

जवाबों:


170

ऐसा इसलिए हो रहा है क्योंकि एंटी-जालसाजी टोकन उपयोगकर्ता के उपयोगकर्ता नाम को बेहतर सत्यापन के लिए एन्क्रिप्टेड टोकन के हिस्से के रूप में एम्बेड करता है। जब आप पहली बार कॉल करते हैं @Html.AntiForgeryToken()तो उपयोगकर्ता लॉग इन नहीं होता है इसलिए उपयोगकर्ता के लॉग इन करने के बाद टोकन में उपयोगकर्ता के लिए एक खाली स्ट्रिंग होगी, यदि आप एंटी-फर्जी टोकन को प्रतिस्थापित नहीं करते हैं तो यह सत्यापन पारित नहीं करेगा क्योंकि प्रारंभिक टोकन था अनाम उपयोगकर्ता और अब हमारे पास एक ज्ञात उपयोगकर्ता नाम वाला एक प्रमाणित उपयोगकर्ता है।

इस समस्या को हल करने के लिए आपके पास कुछ विकल्प हैं:

  1. बस इस बार अपने एसपीए को एक पूर्ण POST करने दें और जब पृष्ठ पुनः लोड होता है तो इसमें अपडेट किए गए उपयोगकर्ता नाम के साथ एक विरोधी जालसाजी टोकन होगा।

  2. @Html.AntiForgeryToken()लॉग इन करने के बाद बस और सही के साथ एक आंशिक दृश्य है, एक और AJAX अनुरोध करें और आपके मौजूदा एंटी-फर्जी टोकन को अनुरोध की प्रतिक्रिया के साथ बदलें।

  3. बस पहचान को निष्क्रिय करें विरोधी जालसाजी सत्यापन कार्य की जांच करें। अपने Application_Start पद्धति में निम्नलिखित जोड़ें AntiForgeryConfig.SuppressIdentityHeuristicChecks = true:।


21
@ संवेदनशीलता: आपने इस उत्तर को स्वीकार कर लिया, क्या आप हमारे साथ साझा कर सकते हैं कि आपने कौन सा विकल्प चुना है?
आर। श्रेयर्स

9
अच्छा और सरल विकल्प के लिए +1 3. OAuth प्रदाताओं द्वारा समयबद्ध लॉगआउट भी इस समस्या का कारण बनते हैं।
चला गया

18
विकल्प 3 ने मेरे लिए काम नहीं किया। जब भी लॉग आउट हुआ, मैंने लॉगिन पेज पर दो विंडो खोलीं। एक विंडो में एक उपयोगकर्ता के रूप में लॉग इन किया, फिर दूसरे उपयोगकर्ता के रूप में लॉग इन किया और वही त्रुटि प्राप्त की।
मैकगज

5
दुर्भाग्य से, मुझे इसका कोई अच्छा समाधान नहीं मिला। मैंने लॉगिन पृष्ठ से टोकन हटा दिया। मैं अभी भी लॉगिन के बाद पोस्ट पर इसे शामिल करता हूं।
मैगज़

7
विकल्प 3 ने न तो मेरे लिए काम किया। अभी भी वही त्रुटि हो रही है।
जोआओ लेम

25

इस त्रुटि को ठीक करने के लिए आपको लॉगिन पृष्ठ OutputCacheपर डेटा एनोटेशन को इस प्रकार रखना होगा ActionResult:

[OutputCache(NoStore=true, Duration = 0, VaryByParam= "None")] 
public ActionResult Login(string returnUrl)

3
यह मेरे लिए इस मुद्दे को हल किया, कुल समझ में आता है। धन्यवाद!
प्राइम

मेरा उपयोग का मामला था, उपयोगकर्ता ने लॉगिन की कोशिश की, और एक त्रुटि दिखाई। उदाहरण के लिए ModelState.AddError () के माध्यम से "खाता अक्षम"। फिर अगर वे दोबारा लॉगिन पर क्लिक करते हैं तो उन्हें यह त्रुटि दिखाई देगी। हालाँकि, इस फिक्स ने उन्हें विरोधी जालसाजी की त्रुटि के बजाय फिर से एक ताज़ा ताज़ा लॉगिन दृश्य दिया। तो, एक तय नहीं।
yourpublicdisplayname

मेरा मामला: 1. उपयोगकर्ता लॉग इन () और होम पेज में भूमि। 2. उपयोगकर्ता वापस बटन हिट करता है और लॉगिन दृश्य पर वापस जाता है। 3. उपयोगकर्ता फिर से लॉग इन करें और त्रुटि देखें "एंटी फर्जी टोकन उपयोगकर्ता के लिए है" "लेकिन वर्तमान उपयोगकर्ता" उपयोगकर्ता नाम "है" त्रुटि पृष्ठ पर यदि उपयोगकर्ता मेनू से किसी अन्य टैब पर क्लिक करता है, तो एप्लिकेशन अपेक्षित रूप से काम कर रहा था। । उपरोक्त कोड उपयोगकर्ता का उपयोग करके अभी भी बैक बटन मारा जा सकता है लेकिन यह होम पेज पर रीडायरेक्ट हो जाता है। कोई फर्क नहीं पड़ता कि उपयोगकर्ता कितनी बार बैक बटन दबाता है वह इसे होम पेज पर रीडायरेक्ट करेगा। धन्यवाद
रवि

किसी भी विचार क्यों यह एक ज़ामरीन वेबव्यू पर काम नहीं करता है?
Noobie3001


15

यह मेरे आवेदन के साथ बहुत बार होता है, इसलिए मैंने इसके लिए Google का फैसला किया!

मुझे इस त्रुटि के बारे में एक सरल स्पष्टीकरण मिला! उपयोगकर्ता लॉगिन के लिए बटन पर डबल-क्लिक कर रहे हैं! आप किसी अन्य उपयोगकर्ता को नीचे दिए गए लिंक पर इस बारे में बात करते हुए देख सकते हैं:

MVC 4 प्रदान किया गया था विरोधी जालसाजी टोकन उपयोगकर्ता के लिए था "" लेकिन वर्तमान उपयोगकर्ता "उपयोगकर्ता" है

मुझे उम्मीद है यह मदद करेगा! =)


यह मेरी समस्या थी। धन्यवाद!
नानू पोनटे

8

मुझे भी यही समस्या थी, और इस गंदे हैक को ठीक कर दिया गया, कम से कम जब तक मैं इसे एक क्लीनर तरीके से ठीक नहीं कर सकता।

    public ActionResult Login(string returnUrl)
    {
        if (AuthenticationManager.User.Identity.IsAuthenticated)
        {
            AuthenticationManager.SignOut();
            return RedirectToAction("Login");
        }

...


1
लगता है कि मैं एक ही समस्या थी। IMO यह हैक नहीं है, यह एक सामान्य बात है जिसे लॉगिन करते समय हम सभी को जांचना चाहिए। यदि उपयोगकर्ता पहले से लॉग इन है, तो बस उसे साइन आउट करें और लॉगिन पेज प्रदर्शित करें। मेरी समस्या का समाधान, धन्यवाद।
एलेक्जेंड्रे

7

जब आप पहले से ही प्रमाणित हो जाते हैं तो आप लॉग इन करते समय संदेश प्रकट होता है।

यह हेल्पर बिल्कुल वैसा ही काम करता है जैसा कि [ValidateAntiForgeryToken]विशेषता है।

System.Web.Helpers.AntiForgery.Validate()

[ValidateAntiForgeryToken]कंट्रोलर से एट्रिब्यूट हटा दें और इस हेल्पर को एक्शन मेथोड में रखें।

इसलिए जब उपयोगकर्ता पहले से ही प्रमाणित हो जाता है, तो होम पेज पर रीडायरेक्ट होता है या यदि इस सत्यापन के बाद वैध एंटी-फर्जी टोकन के सत्यापन के साथ जारी नहीं रहता है।

if (User.Identity.IsAuthenticated)
{
    return RedirectToAction("Index", "Home");
}

System.Web.Helpers.AntiForgery.Validate();

त्रुटि को पुन: उत्पन्न करने का प्रयास करने के लिए, निम्नानुसार आगे बढ़ें: यदि आप अपने लॉगिन पृष्ठ पर हैं और आप प्रमाणित नहीं हैं। यदि आप टैब को डुप्लिकेट करते हैं और आप दूसरे टैब से लॉगिन करते हैं। और यदि आप लॉगिन पृष्ठ पर पहले टैब पर वापस आते हैं और आप पृष्ठ को फिर से लोड किए बिना लॉग इन करने का प्रयास करते हैं ... तो आपके पास यह त्रुटि है।


उत्कृष्ट समाधान! बहुत सारे अन्य सुझावों को आजमाने के बाद इसने मेरे मुद्दे को हल किया जो काम नहीं आया। सबसे पहले यह त्रुटि को दोहराने वाला एक दर्द था, जब तक मुझे पता नहीं चला कि यह एक ही पेज के साथ 2 ब्राउज़र या टैब के खुलने के कारण हो सकता है, और उपयोगकर्ता एक से लॉग इन कर रहा है, और फिर दूसरे से लॉग-इन किए बिना फिर से लोड हो रहा है।
निकी

इस समाधान के लिए धन्यवाद। मेरे लिए भी काम किया। मैंने यह देखने के लिए एक चेक जोड़ा कि क्या पहचान लॉगिन उपयोगकर्ता नाम के समान थी, और यदि मैं खुशी से उपयोगकर्ता को लॉग इन करने का प्रयास जारी रखता हूं और अगर यह नहीं है, तो उन्हें लॉग आउट करें। उदाहरण के लिए, {System.Web.Helpers.AntiForgery.Validate ();} catch (HttpAntiForgeryException) {if ((User.Identity.IsAuthenticated) = string .Compare (User.Identity.Name, model.Username)! = 0) आज़माएँ। {// आपका लॉजिक लॉजिक}}
स्टीव ओवेन

2

मैं एक ही अपवाद उत्पादन सर्वर पर ज्यादातर समय होता है।

क्यों होता है?

ऐसा तब होता है जब उपयोगकर्ता वैध क्रेडेंशियल के साथ लॉगिन करता है और एक बार लॉग इन करता है और दूसरे पृष्ठ पर रीडायरेक्ट करता है, और जब वे बैक बटन दबाते हैं तो लॉगिन पेज दिखाई देगा और फिर से उस समय वह वैध क्रेडेंशियल्स में प्रवेश करेगा, जब यह अपवाद होगा।

कैसे हल करें?

बस इस लाइन को जोड़ें और सही काम करें, कोई त्रुटि नहीं मिलती है।

[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]

1

मुझे पंजीकरण प्रक्रिया के भीतर काफी विशिष्ट अभी तक समान समस्या थी। उपयोगकर्ता द्वारा भेजे गए ईमेल लिंक पर क्लिक करने के बाद, उन्हें लॉग इन किया जाएगा और कुछ और जानकारी भरने के लिए सीधे खाता विवरण स्क्रीन पर भेजा जाएगा। मेरा कोड था:

    Dim result = Await UserManager.ConfirmEmailAsync(userId, code)
    If result.Succeeded Then
        Dim appUser = Await UserManager.FindByIdAsync(userId)
        If appUser IsNot Nothing Then
            Dim signInStatus = Await SignInManager.PasswordSignInAsync(appUser.Email, password, True, shouldLockout:=False)
            If signInStatus = SignInStatus.Success Then
                Dim identity = Await UserManager.CreateIdentityAsync(appUser, DefaultAuthenticationTypes.ApplicationCookie)
                AuthenticationManager.SignIn(New AuthenticationProperties With {.IsPersistent = True}, identity)
                Return View("AccountDetails")
            End If
        End If
    End If

मैंने पाया कि रिटर्न व्यू ("अकाउंटडेलेट्स") मुझे टोकन अपवाद दे रहा था, मैं अनुमान लगा रहा हूं क्योंकि ConfirmEmail फ़ंक्शन को AllowAnonymous के साथ सजाया गया था, लेकिन AccountDetails फ़ंक्शन में ValidateAntiForgeryokoken था।

रिटर्न टू रिटर्न रिडायरेक्टऑक्शन ("अकाउंटडेल्स") को बदलने से मेरे लिए समस्या हल हो गई।


1
[OutputCache(NoStore=true, Duration=0, VaryByParam="None")]

public ActionResult Login(string returnUrl)

आप अपनी लॉगिन (गेट) कार्रवाई की पहली पंक्ति पर एक विराम बिंदु डालकर इसका परीक्षण कर सकते हैं। OutputCache निर्देश को जोड़ने से पहले ब्रेकपॉइंट को पहले लोड पर मारा जाएगा, लेकिन ब्राउज़र बैक बटन पर क्लिक करने के बाद यह नहीं होगा। निर्देश जोड़ने के बाद आपको हर बार ब्रेकपॉइंट के हिट होने के साथ समाप्त होना चाहिए, इसलिए एंटीफॉर्गीटोकन कोर एक होगा, खाली नहीं।


0

मैं एक ही पृष्ठ ASP.NET MVC कोर अनुप्रयोग के साथ एक ही मुद्दा था। मैंने इसे HttpContext.Userसभी नियंत्रक क्रियाओं में सेट करके हल किया जो वर्तमान पहचान के दावों को बदलते हैं (चूंकि एमवीसी केवल बाद के अनुरोधों के लिए ऐसा करता है, जैसा कि यहां चर्चा की गई है )। मैंने अपनी प्रतिक्रियाओं के लिए एंटिफ़ॉर्गरी कुकीज़ को जोड़ने के लिए मिडलवेयर के बजाय एक परिणाम फ़िल्टर का उपयोग किया, जिससे यह सुनिश्चित हो गया कि वे केवल एमवीसी कार्रवाई वापस आने के बाद उत्पन्न हुए थे।

नियंत्रक (NB। मैं ASP.NET कोर पहचान वाले उपयोगकर्ताओं को प्रबंधित कर रहा हूं):

[Authorize]
[ValidateAntiForgeryToken]
public class AccountController : Controller
{
    private SignInManager<IdentityUser> signInManager;
    private UserManager<IdentityUser> userManager;
    private IUserClaimsPrincipalFactory<IdentityUser> userClaimsPrincipalFactory;

    public AccountController(SignInManager<IdentityUser> signInManager, UserManager<IdentityUser> userManager, IUserClaimsPrincipalFactory<ApplicationUser> userClaimsPrincipalFactory)
    {
        this.signInManager = signInManager;
        this.userManager = userManager;
        this.userClaimsPrincipalFactory = userClaimsPrincipalFactory;
    }

    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> Login(string username, string password)
    {
        if (username == null || password == null)
        {
            return BadRequest(); // Alias of 400 response
        }

        var result = await signInManager.PasswordSignInAsync(username, password, false, lockoutOnFailure: false);
        if (result.Succeeded)
        {
            var user = await userManager.FindByNameAsync(username);

            // Must manually set the HttpContext user claims to those of the logged
            // in user. Otherwise MVC will still include a XSRF token for the "null"
            // user and token validation will fail. (MVC appends the correct token for
            // all subsequent reponses but this isn't good enough for a single page
            // app.)
            var principal = await userClaimsPrincipalFactory.CreateAsync(user);
            HttpContext.User = principal;

            return Json(new { username = user.UserName });
        }
        else
        {
            return Unauthorized();
        }
    }

    [HttpPost]
    public async Task<IActionResult> Logout()
    {
        await signInManager.SignOutAsync();

        // Removing identity claims manually from the HttpContext (same reason
        // as why we add them manually in the "login" action).
        HttpContext.User = null;

        return Json(new { result = "success" });
    }
}

एंटीफॉर्जरी कुकीज़ को जोड़ने के लिए परिणाम फ़िल्टर:

public class XSRFCookieFilter : IResultFilter
{
    IAntiforgery antiforgery;

    public XSRFCookieFilter(IAntiforgery antiforgery)
    {
        this.antiforgery = antiforgery;
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var HttpContext = context.HttpContext;
        AntiforgeryTokenSet tokenSet = antiforgery.GetAndStoreTokens(context.HttpContext);
        HttpContext.Response.Cookies.Append(
            "MyXSRFFieldTokenCookieName",
            tokenSet.RequestToken,
            new CookieOptions() {
                // Cookie needs to be accessible to Javascript so we
                // can append it to request headers in the browser
                HttpOnly = false
            } 
        );
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {

    }
}

Startup.cs निकालने:

public partial class Startup
{
    public Startup(IHostingEnvironment env)
    {
        //...
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {

        //...

        services.AddAntiforgery(options =>
        {
            options.HeaderName = "MyXSRFFieldTokenHeaderName";
        });


        services.AddMvc(options =>
        {
            options.Filters.Add(typeof(XSRFCookieFilter));
        });

        services.AddScoped<XSRFCookieFilter>();

        //...
    }

    public void Configure(
        IApplicationBuilder app,
        IHostingEnvironment env,
        ILoggerFactory loggerFactory)
    {
        //...
    }
}

-3

इंटरनेट-शॉप में एंटी-जालसाजी-टोकन सत्यापन के साथ एक समस्या है: उपयोगकर्ता कई टैब खोलते हैं (माल के साथ) और लॉग ऑन करने के बाद एक दूसरे पर लॉग इन करने की कोशिश करते हैं और इस तरह के एंटीफॉरगेरी अपवाद प्राप्त करते हैं। तो, AntiForgeryConfig.SuppressIdentityHeuristicChecks = true ने मेरे लिए मदद नहीं की, इसलिए मैंने ऐसे बदसूरत हैकफ़िक्स का उपयोग किया, शायद यह किसी के लिए उपयोगी होगा:

   public class ExceptionPublisherExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext exceptionContext)
    {
        var exception = exceptionContext.Exception;

        var request = HttpContext.Current.Request;
        if (request != null)
        {
            if (exception is HttpAntiForgeryException &&
                exception.Message.ToLower().StartsWith("the provided anti-forgery token was meant for user \"\", but the current user is"))
            {
                var isAjaxCall = string.Equals("XMLHttpRequest", request.Headers["x-requested-with"], StringComparison.OrdinalIgnoreCase);
                var returnUrl = !string.IsNullOrWhiteSpace(request["returnUrl"]) ? request["returnUrl"] : "/";
                var response = HttpContext.Current.Response;

                if (isAjaxCall)
                {
                    response.Clear();
                    response.StatusCode = 200;
                    response.ContentType = "application/json; charset=utf-8";
                    response.Write(JsonConvert.SerializeObject(new { success = 1, returnUrl = returnUrl }));
                    response.End();
                }
                else
                {
                    response.StatusCode = 200;
                    response.Redirect(returnUrl);
                }
            }
        }


        ExceptionHandler.HandleException(exception);
    }
}

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new ExceptionPublisherExceptionFilter());
        filters.Add(new HandleErrorAttribute());
    }
}

लगता है कि यह बहुत अच्छा होगा यदि एंटी-जालसाजी-टोकन पीढ़ी के विकल्प सेट किए जा सकते हैं, उपयोगकर्ता नाम या ऐसा कुछ बाहर करने के लिए।


12
यह सवाल में समस्या से निपटने का एक भयानक उदाहरण है। यह प्रयोग न करें।
xxbbcc

पूरी तरह से xxbbcc से सहमत हैं।
जेवियर

ठीक है, केस का उपयोग करें: विरोधी जालसाजी टोकन के साथ लॉगिन फ़ॉर्म। इसे 2 ब्राउज़र टैब में खोलें। पहले लॉग इन करें। आप दूसरा टैब ताज़ा नहीं कर सकते । दूसरे टैब से लॉग इन करने का प्रयास करने वाले उपयोगकर्ता के लिए सही व्यवहार करने के लिए आप क्या समाधान सुझाते हैं?
user3364244

@ user3364244: सही व्यवहार निम्नलिखित कर सकता है: वेबस्कॉक या सिग्नलआर का उपयोग करके एक बाहरी लॉगिन का पता लगाएं। यह एक ही सत्र है इसलिए आप इसे काम कर सकते हैं मुझे लगता है :-)
dampee
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.