2016-12-23 3 views
0

複数のリフレッシュトークンを許可するには、どのようにAsp.netコアでopeniddictのカスタムプロバイダを作成しますか?この方法では、ユーザーがコンピュータからログインして家に帰って電話にログインすると、別のデバイスに接続するたびにログインする必要はありません。 app.UseOAuthValidation()はバックグラウンドで実行される前にバックグラウンドで実行されるため、複数のリフレッシュトークンが一致するかどうかを確認するハンドルがありません。もう一つの問題は、私はこれを使用していますということです。Openiddict複数のリフレッシュトークン

services.AddDbContext<ApplicationDbContext>(options => { 
      options.UseMySql(Configuration.GetConnectionString("DefaultConnection")) 
        .UseOpenIddict(); 
     }); 

だから私は手動でこれを行うにはDbContext経由openiddictテーブルにアクセスすることはできません。

Startup.cs

using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Hosting; 
using Microsoft.Extensions.Configuration; 
using Microsoft.Extensions.DependencyInjection; 
using Microsoft.Extensions.Logging; 
using Microsoft.EntityFrameworkCore; 
using DPInventoryPOAPI.Models; 
using Microsoft.AspNetCore.Identity; 
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 
using OpenIddict.Core; 
using OpenIddict.Models; 
using System.Threading; 
using System.Linq; 

namespace DPInventoryPOAPI 
{ 
    public class Startup 
    { 
     public Startup(IHostingEnvironment env) 
     { 
      var builder = new ConfigurationBuilder() 
       .SetBasePath(env.ContentRootPath) 
       .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 
       .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 
       .AddEnvironmentVariables(); 


      Configuration = builder.Build(); 
     } 

     public IConfigurationRoot Configuration { get; } 

     // This method gets called by the runtime. Use this method to add services to the container. 
     public void ConfigureServices(IServiceCollection services) 
     { 
      services.AddCors(options => 
      { 
       options.AddPolicy("CorsPolicy", 
        builder => builder.AllowAnyOrigin() 
        .AllowAnyMethod() 
        .AllowAnyHeader() 
        .AllowCredentials()); 
      }); 

      services.AddMvc(); 

      services.AddDbContext<ApplicationDbContext>(options => { 
       options.UseMySql(Configuration.GetConnectionString("DefaultConnection")) 
        .UseOpenIddict(); 
      }); 

      services.AddIdentity<ApplicationUser, IdentityRole>() 
       .AddEntityFrameworkStores<ApplicationDbContext>() 
       .AddDefaultTokenProviders(); 

      services.AddOpenIddict() 
       .AddEntityFrameworkCoreStores<ApplicationDbContext>() 
       .AddMvcBinders() 
       .EnableTokenEndpoint("/token") 
       .AllowPasswordFlow() 
       .AllowRefreshTokenFlow() 
       .DisableHttpsRequirement() 
       .AddEphemeralSigningKey(); 
     } 

     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 
     public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime, ILoggerFactory loggerFactory) 
     { 
      if (env.IsDevelopment()) 
      { 
       app.UseDeveloperExceptionPage(); 
       app.UseDatabaseErrorPage(); 
       //app.UseBrowserLink(); 
      } 
      else 
      { 
       app.UseExceptionHandler("/Home/Error"); 
      } 


      app.UseCors("CorsPolicy"); 

      app.UseIdentity(); 

      app.UseOpenIddict(); 

      app.UseOAuthValidation(); 

      app.UseMvcWithDefaultRoute(); 

      //SeedDatabase(app); 
     } 
    } 
} 

そして、どのように複数のリフレッシュトークンを許可するようにAsp.netコアにopeniddictのカスタムプロバイダを作成するのですか?コントローラ

using System.Diagnostics; 
using System.Linq; 
using System.Threading.Tasks; 
using AspNet.Security.OpenIdConnect.Extensions; 
using AspNet.Security.OpenIdConnect.Primitives; 
using AspNet.Security.OpenIdConnect.Server; 
using AuthorizationServer.Models; 
using Microsoft.AspNetCore.Authentication; 
using Microsoft.AspNetCore.Http.Authentication; 
using Microsoft.AspNetCore.Identity; 
using Microsoft.AspNetCore.Mvc; 
using OpenIddict.Core; 
using OpenIddict.Models; 

// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 

namespace AuthorizationServer.Controllers { 
public class AuthorizationController : Controller { 
    private readonly OpenIddictApplicationManager<OpenIddictApplication> _applicationManager; 
    private readonly SignInManager<ApplicationUser> _signInManager; 
    private readonly UserManager<ApplicationUser> _userManager; 

    public AuthorizationController(
     OpenIddictApplicationManager<OpenIddictApplication> applicationManager, 
     SignInManager<ApplicationUser> signInManager, 
     UserManager<ApplicationUser> userManager) { 
     _applicationManager = applicationManager; 
     _signInManager = signInManager; 
     _userManager = userManager; 
    } 

    [HttpPost("~/connect/token"), Produces("application/json")] 
    public async Task<IActionResult> Exchange(OpenIdConnectRequest request) { 
     Debug.Assert(request.IsTokenRequest(), 
      "The OpenIddict binder for ASP.NET Core MVC is not registered. " + 
      "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called."); 

     if (request.IsPasswordGrantType()) { 
      var user = await _userManager.FindByNameAsync(request.Username); 
      if (user == null) { 
       return BadRequest(new OpenIdConnectResponse { 
        Error = OpenIdConnectConstants.Errors.InvalidGrant, 
        ErrorDescription = "The username/password couple is invalid." 
       }); 
      } 

      // Ensure the user is allowed to sign in. 
      if (!await _signInManager.CanSignInAsync(user)) { 
       return BadRequest(new OpenIdConnectResponse { 
        Error = OpenIdConnectConstants.Errors.InvalidGrant, 
        ErrorDescription = "The specified user is not allowed to sign in." 
       }); 
      } 

      // Reject the token request if two-factor authentication has been enabled by the user. 
      if (_userManager.SupportsUserTwoFactor && await _userManager.GetTwoFactorEnabledAsync(user)) { 
       return BadRequest(new OpenIdConnectResponse { 
        Error = OpenIdConnectConstants.Errors.InvalidGrant, 
        ErrorDescription = "The specified user is not allowed to sign in." 
       }); 
      } 

      // Ensure the user is not already locked out. 
      if (_userManager.SupportsUserLockout && await _userManager.IsLockedOutAsync(user)) { 
       return BadRequest(new OpenIdConnectResponse { 
        Error = OpenIdConnectConstants.Errors.InvalidGrant, 
        ErrorDescription = "The username/password couple is invalid." 
       }); 
      } 

      // Ensure the password is valid. 
      if (!await _userManager.CheckPasswordAsync(user, request.Password)) { 
       if (_userManager.SupportsUserLockout) { 
        await _userManager.AccessFailedAsync(user); 
       } 

       return BadRequest(new OpenIdConnectResponse { 
        Error = OpenIdConnectConstants.Errors.InvalidGrant, 
        ErrorDescription = "The username/password couple is invalid." 
       }); 
      } 

      if (_userManager.SupportsUserLockout) { 
       await _userManager.ResetAccessFailedCountAsync(user); 
      } 

      // Create a new authentication ticket. 
      var ticket = await CreateTicketAsync(request, user); 

      return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme); 
     } 

     else if (request.IsRefreshTokenGrantType()) { 
      // Retrieve the claims principal stored in the refresh token. 
      var info = await HttpContext.Authentication.GetAuthenticateInfoAsync(
       OpenIdConnectServerDefaults.AuthenticationScheme); 

      // Retrieve the user profile corresponding to the refresh token. 
      var user = await _userManager.GetUserAsync(info.Principal); 
      if (user == null) { 
       return BadRequest(new OpenIdConnectResponse { 
        Error = OpenIdConnectConstants.Errors.InvalidGrant, 
        ErrorDescription = "The refresh token is no longer valid." 
       }); 
      } 

      // Ensure the user is still allowed to sign in. 
      if (!await _signInManager.CanSignInAsync(user)) { 
       return BadRequest(new OpenIdConnectResponse { 
        Error = OpenIdConnectConstants.Errors.InvalidGrant, 
        ErrorDescription = "The user is no longer allowed to sign in." 
       }); 
      } 

      // Create a new authentication ticket, but reuse the properties stored 
      // in the refresh token, including the scopes originally granted. 
      var ticket = await CreateTicketAsync(request, user, info.Properties); 

      return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme); 
     } 

     return BadRequest(new OpenIdConnectResponse { 
      Error = OpenIdConnectConstants.Errors.UnsupportedGrantType, 
      ErrorDescription = "The specified grant type is not supported." 
     }); 
    } 

    private async Task<AuthenticationTicket> CreateTicketAsync(
     OpenIdConnectRequest request, ApplicationUser user, 
     AuthenticationProperties properties = null) { 
     // Create a new ClaimsPrincipal containing the claims that 
     // will be used to create an id_token, a token or a code. 
     var principal = await _signInManager.CreateUserPrincipalAsync(user); 

     // Note: by default, claims are NOT automatically included in the access and identity tokens. 
     // To allow OpenIddict to serialize them, you must attach them a destination, that specifies 
     // whether they should be included in access tokens, in identity tokens or in both. 

     foreach (var claim in principal.Claims) { 
      // In this sample, every claim is serialized in both the access and the identity tokens. 
      // In a real world application, you'd probably want to exclude confidential claims 
      // or apply a claims policy based on the scopes requested by the client application. 
      claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken, 
            OpenIdConnectConstants.Destinations.IdentityToken); 
     } 

     // Create a new authentication ticket holding the user identity. 
     var ticket = new AuthenticationTicket(principal, properties, 
      OpenIdConnectServerDefaults.AuthenticationScheme); 

     if (!request.IsRefreshTokenGrantType()) { 
      // Set the list of scopes granted to the client application. 
      // Note: the offline_access scope must be granted 
      // to allow OpenIddict to return a refresh token. 
      ticket.SetScopes(new[] { 
       OpenIdConnectConstants.Scopes.OpenId, 
       OpenIdConnectConstants.Scopes.Email, 
       OpenIdConnectConstants.Scopes.Profile, 
       OpenIdConnectConstants.Scopes.OfflineAccess, 
       OpenIddictConstants.Scopes.Roles 
      }.Intersect(request.GetScopes())); 
     } 

     return ticket; 
    } 
} 
} 

答えて

1

を承認この方法では、ユーザーがコンピュータからログインして家に帰って電話にログインすると、別のデバイスに接続するたびにログインする必要はありません。

OTBでは、OpenIddictを使用すると、異なるgrant_type=passwordリクエストを使用して要求されている限り、複数の(独立した)リフレッシュトークンを取得できます。あなたのケースでは、モバイルアプリケーションによって取得されたトークンが取り消された場合(たとえば、手動で、または既に使用されているため)、デスクトップアプリケーションによって使用されるリフレッシュトークンを使用して新しいアクセス/リフレッシュトークンを取得できます。

app.UseOAuthValidation()は、承認コントローラが呼び出される前にバックグラウンドで実行されるため、複数のリフレッシュトークンが一致するかどうかを確認するハンドルがありません。

検証ミドルウェアは、アクセストークンの検証のみを担当するため、リフレッシュトークンを扱うことはありません。

私は手動でこれを行うには、DbContext経由でopeniddictテーブルにアクセスする必要はありません。

あなたDbContextDbSet<OpenIddictToken>プロパティを追加したり、context.Set<OpenIddictToken>()経由DbSet<OpenIddictToken>を取得することができます。

関連する問題