2015-11-29 24 views
5

Taiseer Joudeh उत्कृष्ट लेख के बाद
एएसपी नेट जाल एपीआई 2, और Owin (http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/) वर्तमान में मैं ताज़ा टोकन विकल्प के साथ एक टोकन आधारित प्रमाणीकरण बनाने रहा हूँ का उपयोग कर AngularJS अनुप्रयोग में OAuth ताज़ा टोकन सक्षम करें।OAuth 2 ताज़ा टोकन invalid_grant

public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider 
    { 

     public async Task CreateAsync(AuthenticationTokenCreateContext context) 
     { 
      var clientid = context.Ticket.Properties.Dictionary["as:client_id"]; 

      if (string.IsNullOrEmpty(clientid)) 
      { 
       return; 
      } 

      var refreshTokenId = Guid.NewGuid().ToString("n"); 

      using (var _repo = new AuthRepository()) 
      { 
       var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime"); 

       var token = new RefreshToken() 
       { 
        Id = Helper.GetHash(refreshTokenId), 
        ClientId = clientid, 
        Subject = context.Ticket.Identity.Name, 
        IssuedUtc = DateTime.UtcNow, 
        ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime)) 
       }; 

       context.Ticket.Properties.IssuedUtc = token.IssuedUtc; 
       context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc; 

       token.ProtectedTicket = context.SerializeTicket(); 

       var result = await _repo.AddRefreshToken(token); 

       if (result) 
       { 
        context.SetToken(refreshTokenId); 
       } 

      } 
     } 

     public async Task ReceiveAsync(AuthenticationTokenReceiveContext context) 
     { 

      var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin"); 
      context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin }); 

      string hashedTokenId = Helper.GetHash(context.Token); 

      using (var _repo = new AuthRepository()) 
      { 
       var refreshToken = await _repo.FindRefreshToken(hashedTokenId); 

       if (refreshToken != null) 
       { 
        //Get protectedTicket from refreshToken class 
        context.DeserializeTicket(refreshToken.ProtectedTicket); 
        var result = await _repo.RemoveRefreshToken(hashedTokenId); 
       } 
      } 
     } 

     public void Create(AuthenticationTokenCreateContext context) 
     { 
      throw new NotImplementedException(); 
     } 

     public void Receive(AuthenticationTokenReceiveContext context) 
     { 
      throw new NotImplementedException(); 
     } 
    } 

: इस प्रकार

public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider 
    { 
     public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 
     { 

      string clientId = string.Empty; 
      string clientSecret = string.Empty; 
      Client client = null; 

      if (!context.TryGetBasicCredentials(out clientId, out clientSecret)) 
      { 
       context.TryGetFormCredentials(out clientId, out clientSecret); 
      } 

      if (context.ClientId == null) 
      { 
       //Remove the comments from the below line context.SetError, and invalidate context 
       //if you want to force sending clientId/secrects once obtain access tokens. 
       context.Validated(); 
       //context.SetError("invalid_clientId", "ClientId should be sent."); 
       return Task.FromResult<object>(null); 
      } 

      using (AuthRepository _repo = new AuthRepository()) 
      { 
       client = _repo.FindClient(context.ClientId); 
      } 

      if (client == null) 
      { 
       context.SetError("invalid_clientId", string.Format("Client '{0}' is not registered in the system.", context.ClientId)); 
       return Task.FromResult<object>(null); 
      } 

      if (client.ApplicationType == Models.ApplicationTypes.NativeConfidential) 
      { 
       if (string.IsNullOrWhiteSpace(clientSecret)) 
       { 
        context.SetError("invalid_clientId", "Client secret should be sent."); 
        return Task.FromResult<object>(null); 
       } 
       else 
       { 
        if (client.Secret != Helper.GetHash(clientSecret)) 
        { 
         context.SetError("invalid_clientId", "Client secret is invalid."); 
         return Task.FromResult<object>(null); 
        } 
       } 
      } 

      if (!client.Active) 
      { 
       context.SetError("invalid_clientId", "Client is inactive."); 
       return Task.FromResult<object>(null); 
      } 

      context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin); 
      context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString()); 

      context.Validated(); 
      return Task.FromResult<object>(null); 
     } 

     public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
     { 

      var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin"); 

      if (allowedOrigin == null) allowedOrigin = "*"; 

      context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin }); 
      //var id = ""; 
      using (AuthRepository _repo = new AuthRepository()) 
      { 
       IdentityUser user = await _repo.FindUser(context.UserName, context.Password); 

       if (user == null) 
       { 
        context.SetError("invalid_grant", "The user name or password is incorrect."); 
        return; 
       } 
       //Here set User.Identity.Id = RavenUserId, So rest of the user will be able to get it 
       //id = (user == null ? "0" : user.RavenUserId.ToString()); 
      } 

      var identity = new ClaimsIdentity(context.Options.AuthenticationType); 
      identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName)); 
      //So when we will call User.Identity.Id we will be able to get Raven User Id 
      // identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, id)); 
      identity.AddClaim(new Claim("sub", context.UserName)); 
      identity.AddClaim(new Claim("role", "user")); 

      var props = new AuthenticationProperties(new Dictionary<string, string> 
       { 
        { 
         "as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId 
        }, 
        { 
         "userName", context.UserName 
        } 
       }); 

      var ticket = new AuthenticationTicket(identity, props); 
      context.Validated(ticket); 

     } 

     public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context) 
     { 
      var originalClient = context.Ticket.Properties.Dictionary["as:client_id"]; 
      var currentClient = context.ClientId; 

      if (originalClient != currentClient) 
      { 
       context.SetError("invalid_clientId", "Refresh token is issued to a different clientId."); 
       return Task.FromResult<object>(null); 
      } 

      // Change auth ticket for refresh token requests 
      var newIdentity = new ClaimsIdentity(context.Ticket.Identity); 

      var newClaim = newIdentity.Claims.Where(c => c.Type == "newClaim").FirstOrDefault(); 
      if (newClaim != null) 
      { 
       newIdentity.RemoveClaim(newClaim); 
      } 
      newIdentity.AddClaim(new Claim("newClaim", "newValue")); 

      var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties); 
      context.Validated(newTicket); 

      return Task.FromResult<object>(null); 
     } 


     public override Task TokenEndpoint(OAuthTokenEndpointContext context) 
     { 
      foreach (KeyValuePair<string, string> property in context.Properties.Dictionary) 
      { 
       context.AdditionalResponseParameters.Add(property.Key, property.Value); 
      } 

      return Task.FromResult<object>(null); 
     } 
    } 

मेरे SimpleRefreshTokenProvider वर्ग कोड है: इस प्रकार

public class Startup 
    { 
     public void Configuration(IAppBuilder app) 
     { 
      HttpConfiguration config = new HttpConfiguration(); 

      ConfigureOAuth(app); 

      WebApiConfig.Register(config); 
      app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); 
      app.UseWebApi(config); 
     } 

     public void ConfigureOAuth(IAppBuilder app) 
     { 

      OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions() 
      { 

       AllowInsecureHttp = true, 
       TokenEndpointPath = new PathString("/token"), 
       AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30), 
       Provider = new SimpleAuthorizationServerProvider(), 
       RefreshTokenProvider = new SimpleRefreshTokenProvider() 
      }; 

      // Token Generation 
      app.UseOAuthAuthorizationServer(oAuthServerOptions); 
      app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); 

     } 
    } 

मेरे SimpleAuthorizationServerProvider वर्ग कोड है:

मेरे स्टार्टअप वर्ग कोड इस प्रकार है AuthRepository क्लास कोड निम्नानुसार है:

public class AuthRepository : IDisposable 
    { 
     private AuthContext _ctx; 

     private UserManager<IdentityUser> _userManager; 

     public AuthRepository() 
     { 
      _ctx = new AuthContext(); 
      _userManager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(_ctx)); 
     } 

     public async Task<IdentityResult> RegisterUser(UserModel userModel) 
     { 
      IdentityUser user = new IdentityUser 
      { 
       UserName = userModel.UserName 
      }; 

      var result = await _userManager.CreateAsync(user, userModel.Password); 

      return result; 
     } 

     public async Task<IdentityUser> FindUser(string userName, string password) 
     { 
      IdentityUser user = await _userManager.FindAsync(userName, password); 

      return user; 
     } 


     public Client FindClient(string clientId) 
     { 
      var client = _ctx.Clients.Find(clientId); 
      //var clients = _ctx.Clients; 
      //var client = _ctx.Clients.FirstOrDefault(x => x.Id==clientId); 
      return client; 
     } 

     public async Task<bool> AddRefreshToken(RefreshToken token) 
     { 

      var existingToken = _ctx.RefreshTokens.Where(r => r.Subject == token.Subject && r.ClientId == token.ClientId).SingleOrDefault(); 

      if (existingToken != null) 
      { 
       var result = await RemoveRefreshToken(existingToken); 
      } 

      _ctx.RefreshTokens.Add(token); 

      return await _ctx.SaveChangesAsync() > 0; 
     } 

     public async Task<bool> RemoveRefreshToken(string refreshTokenId) 
     { 
      var refreshToken = await _ctx.RefreshTokens.FindAsync(refreshTokenId); 

      if (refreshToken != null) 
      { 
       _ctx.RefreshTokens.Remove(refreshToken); 
       return await _ctx.SaveChangesAsync() > 0; 
      } 

      return false; 
     } 

     public async Task<bool> RemoveRefreshToken(RefreshToken refreshToken) 
     { 
      _ctx.RefreshTokens.Remove(refreshToken); 
      return await _ctx.SaveChangesAsync() > 0; 
     } 

     public async Task<RefreshToken> FindRefreshToken(string refreshTokenId) 
     { 
      var refreshToken = await _ctx.RefreshTokens.FindAsync(refreshTokenId); 

      return refreshToken; 
     } 

     public List<RefreshToken> GetAllRefreshTokens() 
     { 
      return _ctx.RefreshTokens.ToList(); 
     } 


     public void Dispose() 
     { 
      _ctx.Dispose(); 
      _userManager.Dispose(); 

     } 
    } 

और अजाक्स कोड है:

$("#refresh").click(function() { 
       var token = sessionStorage.getItem(tokenKey); 
       var refresh = sessionStorage.getItem('isRefreshToken'); 
       var refreshToken = sessionStorage.getItem('refreshToken'); 

       if (refresh) { 
        var refreshdata = "grant_type=refresh_token&refresh_token=" + refreshToken + "&client_id=TokenBasedAuthentication"; 
        console.log(refreshdata); 

        sessionStorage.setItem(tokenKey, ''); 
        sessionStorage.setItem(isRefreshToken, ''); 
        sessionStorage.setItem(refreshToken, ''); 

        $.ajax({ 
         url: '/token', 
         type: 'POST', 
         data: refreshdata, 
         headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 
         success: function (data) { 

          sessionStorage.setItem(tokenKey, data.access_token); 
          sessionStorage.setItem(isRefreshToken, true); 
          sessionStorage.setItem(refreshToken, data.refresh_token); 

         }, 
         error: function (xhr) { 
          alert(xhr.status + ': ' + xhr.statusText); 
         } 

        }); 
       } 

      }); 

अंत में जब मैं ताज़ा पर क्लिक करें यह मुझे देता है त्रुटि निम्न त्रुटि: "invalid_grant"

अंतिम दो दिन मैंने कोशिश की यह पता लगाने की परंतु विफल हो गया।

+0

मैं एक ही मुद्दे से अटक गया हूं। क्या आपको इसका कोई समाधान मिला? –

उत्तर

1

इसे आजमाएं। SimpleAuthorizationServerProvider कक्षा के GrantRefreshToken फ़ंक्शन से newIdentity.AddClaim(new Claim("newClaim", "newValue")); कोड की इस पंक्ति को निकालें। चूंकि इस लाइन का कोई उपयोग नहीं है। जब आप नए रीफ्रेश टोकन के लिए अनुरोध करते हैं तो यह दावे को डुप्लिकेट कर रहा है। तो यह आप का विरोध कर रहा है।

+0

यह काम नहीं किया। –

3

मुझे एक समस्या थी जहां मुझे हमेशा एक अवैध_ग्रैंट त्रुटि मिल रही थी, भले ही मुझे पता था कि refresh_token मान्य था। अनुमोदित कई कारण हैं कि अवैध_ग्रेंट त्रुटि क्यों हो सकती है, लेकिन कोड के माध्यम से डीबग करने के बाद मुझे पता चला कि मेरी समस्या CreateAsync विधि में थी। रीफ्रेश टोकन लाइफटाइम वैरिएबल शून्य था। इस प्रकार, जब RefreshToken बनाया जाता है, तो ExpiresUtc मान पहले ही समाप्त हो चुका है, जिससे अवैध_ग्रेंट त्रुटि उत्पन्न होती है। इसे हल करने के लिए मैंने सत्यापित किया कि मेरे पास refreshTokenLifetime चर के लिए मान्य मान था।

var refreshTokenLifetime = context.OwinContext.Get<string>("as:RefreshTokenLifetime") ?? "60"; 
+0

मुझे लगता है कि ऐसी कई समस्याएं हो सकती हैं जो क्रूर रूप से अस्पष्ट "अवैध_ग्रैंट" पकड़-सभी त्रुटि का कारण बनती हैं, लेकिन मुझे यह समस्या थी और यह पता चला कि आपका जवाब यहां पैसे पर सही था !! मेरे मामले में मुझे शब्दकोश में 'लाइफटाइम' की सेटिंग और 'लाइफटाइम' को पुनः प्राप्त करने के बीच मामला अंतर था !! जैसे-जैसे मैं ट्यूटोरियल का अनुसरण कर रहा था, मैं सोच रहा था कि "इन चाबियों के लिए स्थिरांक का उपयोग न करने से परेशानी होती है *" ... और देखो और देखो !! :) मेरा कार्यान्वयन अब पूरी तरह से काम कर रहा है !! धन्यवाद !! – Deltics

संबंधित मुद्दे