asp.net mvc - net - ¿Combina el uso de la autenticación tanto para las páginas MVC como para las páginas de la API web?
controller asp net core 2 (5)
A partir de sus comentarios anteriores, según tengo entendido, tiene un escenario en el que realiza el inicio de sesión a través del navegador, pero también tiene que invocar métodos web-api utilizando llamadas ajax.
Las llamadas del navegador están basadas en cookies de sesión. Si bien las llamadas ajax desde el navegador tendrían la cookie de sesión en el encabezado, lo que se requiere es que el encabezado de autenticación esté presente para que la web-api realice la validación.
Por lo tanto, en un inicio de sesión exitoso también tendría que generar un token basado en web-api, configurarlo como una cookie (a la que se puede acceder mediante javascript) y luego, al realizar llamadas ajax, recogerlo de la cookie e incluirlo como encabezado en su encabezado ''Autorización''.
Tengo una aplicación web MVC 5 y puedo iniciar sesión con una página Login.cshtml y obtener una cookie y el inicio de sesión funciona bien. Pero, me gustaría hacer un inicio de sesión con la API web y luego (tal vez) configurar una cookie para iniciar sesión en mis páginas MVC ... (o iniciar sesión con el inicio de sesión MVC y luego acceder a la API web). web api devuelve un token de portador y no un token de cookie ... así que esto no funciona. ¿Hay alguna manera de combinar el uso de la autenticación tanto para mis páginas de MVC como para mis páginas de la API web?
ACTUALIZAR:
Esto no es realmente un problema de código, más que un problema conceptual.
Las páginas web normales de MVC examinan una cookie llamada, de forma predeterminada, ".AspNet.ApplicationCookie" para determinar la identidad de los solicitantes. Esta cookie se genera llamando a ApplicationSignInManager.PasswordSignInAsync.
Las llamadas de WebAPI, por otro lado, examinan los encabezados de las solicitudes de un elemento llamado Autorización ... y utilizan ese valor para determinar la identidad de los solicitantes. Esto se devuelve de una llamada de WebAPI a "/ Token".
Estos son valores muy diferentes. Mi sitio web necesita usar tanto páginas de MVC como llamadas de WebAPI (para actualizar dinámicamente esas páginas) ... y ambos deben estar autenticados para realizar sus tareas.
El único método que se me ocurre es autenticar dos veces ... una vez con una llamada de WebAPI y otra vez con la publicación de inicio de sesión. (ver mi respuesta abajo).
Esto parece muy intrincado ... pero no entiendo el código de autorización lo suficiente como para saber si existe una forma más adecuada de lograrlo.
Supongo que lo que estás tratando de hacer es que las páginas servidas por MVC tengan javascript que haga llamadas a los métodos de la API web. Si está utilizando la Identidad ASP.NET para manejar la autenticación (lo que parece que está haciendo), entonces MVC debería usar los tokens de OAuth que se pueden pasar a la API web para la autenticación.
Aquí hay un fragmento de un código javascript que me funciona en una situación similar:
var token = sessionStorage.getItem(''access_token'');
var headers = {};
if (token) {
headers.Authorization = ''Bearer '' + token;
}
$.ajax({
type: <GET/POSt/...>,
url: <your api>,
headers: headers
}).done(function (result, textStatus) {
Tengo un caso similar con usted, pero uso una forma diferente de autenticar.
Tengo una web y una api, todas para usuarios de intranet. No uso la identidad del usuario para pasar web y api. En su lugar, creé una cuenta web individual, y cada vez que web utilizará esta cuenta especial para conectarse a api.
Porque también debemos asegurarnos de que los usuarios no deben conectarse a la API directamente. Sólo deben conectarse a la interfaz de usuario web.
Espero que esto te ayude.
Ugg ... lo que tuve que hacer fue usar el formulario Login.cshtml y anular el envío ... hacer una llamada Ajax para obtener el token de portador WebApi ... y luego enviar el formulario para obtener la cookie MVC real. Entonces, en realidad estoy haciendo dos solicitudes de inicio de sesión ... una para el token de WebApi y la otra para la cookie MVC.
Me parece bastante intrépido ... sería bueno si hubiera alguna forma de iniciar sesión en MVC utilizando el token de portador ... o una llamada a WebApi que me devuelva una cookie que puedo usar para las solicitudes de página normales de MVC. .
Si alguien tiene una mejor manera, me encantaría escucharla.
Este es el código de script que agregué a Login.cshtml:
$(document).ready(function () {
$(''form:first'').submit(function (e) {
e.preventDefault();
var $form = $(this);
var formData = $form.serializeObject(); // https://github.com/macek/jquery-serialize-object
formData.grant_type = "password";
$.ajax({
type: "POST",
url: ''@Url.Content("~/Token")'',
dataType: "json",
data: formData, // seems like the data must be in json format
success: function (data) {
sessionStorage.setItem(''token'', data.access_token);
$form.get(0).submit(); // do the actual page post now
},
error: function (textStatus, errorThrown) {
}
});
});
});
La mejor manera de lograrlo es tener un servidor de autorización (una API web que genere un token) y un software intermedio de consumo de token en su proyecto MVC. IdentityServer debería ayudar. Sin embargo lo he hecho así:
Construí un servidor de autorización utilizando JWT con API web y ASP.Net Identity como se explica here .
Una vez que hagas eso, tus API web startup.cs
se verán así:
// Configures cookie auth for web apps and JWT for SPA,Mobile apps
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
// Configure the db context, user manager and role manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
// Cookie for old school MVC application
var cookieOptions = new CookieAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
CookieHttpOnly = true, // JavaScript should use the Bearer
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/api/Account/Login"),
CookieName = "AuthCookie"
};
// Plugin the OAuth bearer JSON Web Token tokens generation and Consumption will be here
app.UseCookieAuthentication(cookieOptions);
OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(30),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat(ConfigurationManager.AppSettings["JWTPath"])
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
Puede encontrar las clases CustomOAuthProvider
y CustomJwtFormat
here .
Escribí una lógica de consumo (es decir, middleware) en todas mis otras API (servidores de recursos) que quería proteger usando el mismo token. Como desea consumir el token generado por la API web en su proyecto MVC, después de implementar el servidor de autorización, necesita lo siguiente:
En su aplicación MVC, agregue esto en startup.cs
:
public void Configuration(IAppBuilder app)
{
ConfigureOAuthTokenConsumption(app);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
var issuer = ConfigurationManager.AppSettings["AuthIssuer"];
string audienceid = ConfigurationManager.AppSettings["AudienceId"];
byte[] audiencesecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);
app.UseCookieAuthentication(new CookieAuthenticationOptions { CookieName = "AuthCookie" , AuthenticationType=DefaultAuthenticationTypes.ApplicationCookie });
//// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Passive,
AuthenticationType = "JWT",
AllowedAudiences = new[] { audienceid },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audiencesecret)
}
});
}
En su controlador MVC, cuando reciba el token, dessialice y genere una cookie a partir del token de acceso:
AccessClaims claimsToken = new AccessClaims();
claimsToken = JsonConvert.DeserializeObject<AccessClaims>(response.Content);
claimsToken.Cookie = response.Cookies[0].Value;
Request.Headers.Add("Authorization", "bearer " + claimsToken.access_token);
var ctx = Request.GetOwinContext();
var authenticateResult = await ctx.Authentication.AuthenticateAsync("JWT");
ctx.Authentication.SignOut("JWT");
var applicationCookieIdentity = new ClaimsIdentity(authenticateResult.Identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
ctx.Authentication.SignIn(applicationCookieIdentity);
Genere una clave de máquina y agréguela a web.config
de su sitio web de API y ASP.Net MVC.
Con esto, se creará una cookie y el atributo [Authorize]
en el sitio MVC y la API web aceptarán esta cookie.
PS He hecho esto con un JWT (servidor de autorización o servidor de autenticación y recursos) de API web y pude consumirlo en un sitio web de MVC de ASP.Net, Sitio de SPA construido en API Angular, API seguras construidas en python (servidor de recursos), Spring (servidor de recursos) y una aplicación de Android.