2016-12-23 2 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); 
     } 
    } 
} 

그리고

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

어떻게 여러 새로 고침 토큰을 허용하는 Asp.net 코어에 openiddict에 대한 사용자 지정 공급자를 만들려면 어떻게해야합니까 컨트롤러 인증을? 이렇게하면 사용자가 컴퓨터에서 로그인 한 다음 집에 가서 휴대 전화에 로그인하면 다른 장치에 연결할 때마다 로그인 할 필요가 없습니다.

OTB는 OpenIddict는 서로 다른 grant_type=password 요청을 사용하여 요청하는대로 한 토큰을 복수 (독립)를 검색 새로 고칠 수 있습니다. 사용자의 경우 모바일 앱에서 검색 한 토큰이 취소 된 경우 (예 : 수동으로 또는 이미 사용 되었기 때문에) 데스크톱 앱에서 사용한 새로 고침 토큰을 사용하여 새로운 액세스/새로 고침 토큰을 검색 할 수 있습니다. 1 개 이상 새로 고침 토큰이 일치하면 확인 할 손잡이가 없기 때문에

app.UseOAuthValidation()는 지금까지 호출되는 권한 부여 컨트롤러 전에 백그라운드에서 실행됩니다.

유효성 검사 미들웨어는 액세스 토큰의 유효성 검사 만 담당하므로 새로 고침 토큰을 처리하지 않습니다.

그래서이 작업을 수동으로 수행하려면 DbContext를 통해 openiddict 테이블에 액세스 할 필요가 없습니다.

당신은 당신의 DbContextDbSet<OpenIddictToken> 속성을 추가하거나 context.Set<OpenIddictToken>()를 통해 DbSet<OpenIddictToken>를 검색 할 수 있습니다.