2016-01-15 6 views
1

Я работаю над образцом приложения OpenIddict с помощью AngularJs. Мне сказали, что вы не должны использовать клиентские фреймворки, такие как Satellizer, поскольку это не рекомендуется, но вместо этого разрешите серверу иметь дело с протоколированием на стороне сервера (локально и с использованием внешних поставщиков входа) и вернуть токен доступа.OpenIddict - Как получить токен доступа для пользователя?

Ну, у меня есть приложение для демонстрации angularJs и использует логику входа на сервер и обращается к угловому приложению, но моя проблема в том, как получить токен доступа для текущего пользователя?

вот мой файл startup.cs, так что вы можете увидеть мою конфигурацию до сих пор

public void ConfigureServices(IServiceCollection services) { 
    var configuration = new ConfigurationBuilder() 
     .AddJsonFile("config.json") 
     .AddEnvironmentVariables() 
     .Build(); 

    services.AddMvc(); 

    services.AddEntityFramework() 
     .AddSqlServer() 
     .AddDbContext<ApplicationDbContext>(options => 
      options.UseSqlServer(configuration["Data:DefaultConnection:ConnectionString"])); 

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

    services.AddTransient<IEmailSender, AuthMessageSender>(); 
    services.AddTransient<ISmsSender, AuthMessageSender>(); 
} 

public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
{ 
    env.EnvironmentName = "Development"; 

    var factory = app.ApplicationServices.GetRequiredService<ILoggerFactory>(); 
    factory.AddConsole(); 
    factory.AddDebug(); 

    app.UseDeveloperExceptionPage(); 

    app.UseIISPlatformHandler(options => { 
     options.FlowWindowsAuthentication = false; 
    }); 

    app.UseOverrideHeaders(options => { 
     options.ForwardedOptions = ForwardedHeaders.All; 
    }); 

    app.UseStaticFiles(); 

    // Add a middleware used to validate access 
    // tokens and protect the API endpoints. 
    app.UseOAuthValidation(); 

    // comment this out and you get an error saying 
    // InvalidOperationException: No authentication handler is configured to handle the scheme: Microsoft.AspNet.Identity.External 
    app.UseIdentity(); 

    // TOO: Remove 
    app.UseGoogleAuthentication(options => { 
     options.ClientId = "XXX"; 
     options.ClientSecret = "XXX"; 
    }); 

    app.UseTwitterAuthentication(options => { 
     options.ConsumerKey = "XXX"; 
     options.ConsumerSecret = "XXX"; 
    }); 

    // Note: OpenIddict must be added after 
    // ASP.NET Identity and the external providers. 
    app.UseOpenIddict(options => 
    { 
     options.Options.AllowInsecureHttp = true; 
     options.Options.UseJwtTokens(); 
    }); 

    app.UseMvcWithDefaultRoute(); 

    using (var context = app.ApplicationServices.GetRequiredService<ApplicationDbContext>()) { 
     context.Database.EnsureCreated(); 

     // Add Mvc.Client to the known applications. 
     if (!context.Applications.Any()) { 
      context.Applications.Add(new Application { 
       Id = "myClient", 
       DisplayName = "My client application", 
       RedirectUri = "http://localhost:5000/signin", 
       LogoutRedirectUri = "http://localhost:5000/", 
       Secret = Crypto.HashPassword("secret_secret_secret"), 
       Type = OpenIddictConstants.ApplicationTypes.Confidential 
      }); 

      context.SaveChanges(); 
     } 
    } 
} 

Теперь мой AccountController в основном так же, как нормальный контроллер счета, хотя когда пользователи вошли в систему (с использованием местных и external signin) Я использую эту функцию и нуждаюсь в accessToken.

private IActionResult RedirectToAngular() 
{ 
    // I need the accessToken here 

    return RedirectToAction(nameof(AccountController.Angular), new { accessToken = token }); 
} 

Как видно из метода ExternalLoginCallback на AccountController

public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null) 
{ 
    var info = await _signInManager.GetExternalLoginInfoAsync(); 
    if (info == null) 
    { 
     return RedirectToAction(nameof(Login)); 
    } 

    // Sign in the user with this external login provider if the user already has a login. 
    var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false); 
    if (result.Succeeded) 
    { 
     // SHOULDNT THE USER HAVE A LOCAL ACCESS TOKEN NOW?? 
     return RedirectToAngular(); 
    } 
    if (result.RequiresTwoFactor) 
    { 
     return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl }); 
    } 
    if (result.IsLockedOut) 
    { 
     return View("Lockout"); 
    } 
    else { 
     // If the user does not have an account, then ask the user to create an account. 
     ViewData["ReturnUrl"] = returnUrl; 
     ViewData["LoginProvider"] = info.LoginProvider; 
     var email = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Email); 
     return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email }); 
    } 
} 

ответ

2
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false); 
if (result.Succeeded) 
{ 
    // SHOULDNT THE USER HAVE A LOCAL ACCESS TOKEN NOW?? 
    return RedirectToAngular(); 
} 

Это не так, как это должно работать. Вот что происходит в классическом потоке:

  • клиентское приложение OAuth2/OpenID Connect (в вашем случае, ваш Satellizer JS приложение) перенаправляет пользователя агента к конечной точке авторизации (/connect/authorize по умолчанию в OpenIddict) со всеми обязательные параметры: client_id, redirect_uri (обязательно в OpenID Connect), response_type и nonce при использовании неявного потока (то есть response_type=id_token token). Satellizer должен сделать это для вас, предположив, что вы правильно зарегистрировали свой сервер авторизации (1).

  • Если пользователь еще не вошел в систему, конечная точка авторизации перенаправляет пользователя в конечную точку входа (в OpenIddict это делается для вас внутренним контроллером). На этом этапе вызывается действие AccountController.Login, и пользователю отображается форма входа.

  • Когда пользователь вошел в систему (после процесса регистрации и/или внешней ассоциации аутентификации), он/она ДОЛЖЕН быть перенаправлен обратно в конечную точку авторизации: вы не можете перенаправить пользовательский агент в свое угловое приложение на этом этапе. Отменить изменения, внесенные в ExternalLoginCallback, и это должно сработать.

  • Затем пользователю отображается форма согласия, указывающая, что он/она собирается разрешить вашему JS-приложению получать доступ к своим личным данным от его имени. Когда пользователь отправляет форму согласия, запрос обрабатывается OpenIddict, создается токен доступа, а пользовательский агент перенаправляется обратно в приложение-клиент JS, а токен добавляется к фрагменту URI.

[1]: в соответствии с документацией Satellizer, это должно быть что-то вроде этого:

$authProvider.oauth2({ 
    name: 'openiddict', 
    clientId: 'myClient', 
    redirectUri: window.location.origin + '/done', 
    authorizationEndpoint: window.location.origin + '/connect/authorize', 
    responseType: 'id_token token', 
    scope: ['openid'], 
    requiredUrlParams: ['scope', 'nonce'], 
    nonce: function() { return "TODO: implement appropriate nonce generation and validation"; }, 
    popupOptions: { width: 1028, height: 529 } 
}); 
Смежные вопросы