2015-11-29 31 views
5


anda ben yenileme jetonu seçeneğiyle Simgesi tabanlı kimlik doğrulamayı oluşturma ASP.NET Web API 2 ve Owin (http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/) kullanılarak angularjs Uygulaması'nda OAuth Yenile Simgelerinizi etkinleştirin.OAuth 2 yenileme Taiseer Joudeh mükemmel makalesinde takiben belirteç 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(); 
     } 
    } 

şu şekildedir:

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); 
     } 
    } 

Benim SimpleRefreshTokenProvider sınıfı kodu şu şekildedir:

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()); 

     } 
    } 

Benim SimpleAuthorizationServerProvider sınıfı kodu şu şekildedir:

My Başlangıç ​​sınıfı kodudur AuthRepository sınıf kodu aşağıdaki gibidir:

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(); 

     } 
    } 

Ve ajax kodu: Ben Yenile tıklayın Nihayet

$("#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); 
         } 

        }); 
       } 

      }); 

o hatayı bana aşağıdaki hata verir: "invalid_grant"

denedim

Son iki gün anlamaya ama başarısız oldu.

+0

aynı sorunla ilgili şaşırıp. Buna bir çözüm buldun mu? –

cevap

1

Bunu deneyin. newIdentity.AddClaim(new Claim("newClaim", "newValue")); kod satırını sınıfının GrantRefreshToken işlevinden kaldırın. Bu hat kullanılmadığı için. Yeni yenileme belirteci isteğinde bulunduğunuzda bu talebi çoğaltıyor. Yani sana karşı çıkıyor.

+0

Bu işe yaramadı. –

3

refresh_token öğesinin geçerli olduğunu bilsem de her zaman bir geçersiz_grant hatası aldığım bir sorunla karşılaştım. Geçersiz_grant hatası olabileceğinin bir çok nedeni var, ancak kodda hata ayıkladıktan sonra, sorunumun CreateAsync yönteminde olduğunu keşfettim. RefreshTokenLifetime değişkeni null. Böylece, RefreshToken oluşturulduğunda, ExpiresUtc değeri geçersiz ve geçersiz_grant hatasına neden oluyor. Bunu çözmek için refreshTokenLifetime değişkeni için geçerli bir değere sahip olduğumu doğruladım.

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

Ben fışkırtıcı belirsiz "invalid_grant" yakalamak tüm hataya yol açan herhangi bir sayı sorun olabilir düşünüyorum, ama bu sorun vardı ve cevabınız burada para üzerinde haklı çıktı çıktı! Benim durumumda, sözlükte '..Lifetime' ayarı ve' LifeTime'ı alma arasında bir vaka farkı vardı! Öğreticiyi takip ederken, "bu anahtarlar için sabitleri kullanmamak, sorun için * sormuyor" diye düşünüyordum. :) Uygulamam şimdi mükemmel çalışıyor! Teşekkür ederim !! – Deltics