Combiner l'utilisation de l'authentification à la fois pour les pages MVC et pour les pages API Web?
j'ai une application web MVC 5 et je peux me connecter avec un Login.CSHTML page et obtenir un cookie et le login fonctionne très bien. Mais, je voudrais faire une connexion avec L'API Web et ensuite (peut-être) définir un cookie de sorte que je suis connecté pour mes pages MVC... cependant, l'api web renvoie un token porteur et non un token cookie... si cela ne fonctionne pas. Y a-t-il un moyen de combiner l'utilisation de l'authentification à la fois pour mes pages MVC et pour mon API Web? pages?
mise à jour:
ce n'est pas vraiment un problème de code, c'est plutôt un problème conceptuel.
Normal MVC Web pages examine un cookie nommé, par défaut,".AspNet.ApplicationCookie" pour déterminer les demandeurs d'identité. Ce cookie est généré en appelant ApplicationSignInManager.PasswordSignInAsync.
les appels WebAPI, d'autre part, examinent les en-têtes des requêtes pour un article nommé Authorization... et utilise cette valeur pour déterminer les demandeurs identité. Ceci est retourné d'un appel WebAPI à "/Token".
ce sont des valeurs très différentes. Mon site Web doit utiliser les deux pages MVC et appels WebAPI (pour mettre à jour dynamiquement ces pages)... et les deux doivent être authentifiés pour accomplir leurs tâches.
la seule méthode à laquelle je peux penser est de réellement s'authentifier deux fois... une fois avec un appel WebAPI et de nouveau avec le Login post. (voir ma Réponse ci-dessous).
Cela semble très hacky... mais je n'ai pas comprenez le code d'autorisation assez pour savoir s'il y a une façon plus appropriée d'accomplir ceci.
6 réponses
la meilleure façon d'y parvenir, est d'avoir un serveur d'autorisation (une API Web générant un token) et une consommation de token middle-ware dans votre projet MVC. IdentityServer devrait aider. Toutefois, j'ai fait comme ceci:
j'ai construit un serveur d'autorisation en utilisant JWT avec L'API Web et ASP.Net identité telle qu'expliquée ici.
une fois que vous avez fait cela, votre API Web startup.cs
ressemblera à ceci:
// 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);
}
vous pouvez trouver le CustomOAuthProvider
et CustomJwtFormat
classes ici.
j'ai écrit une logique de consommation (middleware) dans tous mes autres API (serveurs de ressources) que je voulais sécuriser en utilisant le même token. Puisque vous voulez consommer le token généré par L'API Web dans votre projet MVC, après avoir implémenté le serveur d'autorisation, vous devez:
dans votre application MVC, ajoutez ceci dans 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)
}
});
}
dans votre contrôleur MVC, lorsque vous recevez le token, désérialisez - le et générez un cookie à partir du token d'accès:
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);
générer une touche machine et l'ajouter dans web.config
de votre API Web et ASP.Net site MVC.
avec ceci, un cookie sera créé et le [Authorize]
attribut dans le site MVC et L'API Web honorera ce cookie.
P.S. j'ai fait cela avec une API Web émettant JWT (Authorization server ou Auth & resource server) et j'ai pu le consommer dans un ASP.Net site Web de MVC, Site SPA Construit en Angular, APIs sécurisé construit en python (resource server), Le printemps (resource server) et une application Android.
Ugg... ce que j'avais à faire était d'utiliser le Login.CSHTML form et Outrepasser le submit... faites un appel Ajax pour obtenir le jeton porteur WebApi... et ensuite faire le formulaire Soumettre pour obtenir le cookie MVC réelle. Donc, je fais en fait deux demandes de connexion... une pour le token WebApi et l'autre pour le cookie MVC.
Semblent assez hacky pour moi... ce serait bien s'il y avait un moyen de s'inscrire à MVC en utilisant le jeton porteur... ou un appel au WebApi qui me rendrait un cookie que je peux utiliser pour les requêtes de page MVC normales.
Si quelqu'un a une meilleure façon que j'aimerais l'entendre.
c'est le code de script que j'ai ajouté à 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) {
}
});
});
});
je suppose que ce que vous essayez de faire est d'avoir des pages servies par MVC avec javascript qui fait des appels vers des méthodes D'API Web. Si vous utilisez ASP.NET Identity to handle authentication (ce que l'on dirait que vous faites), alors MVC devrait utiliser des tokens OAuth qui peuvent être passés à L'API Web pour authentification.
Voici un extrait de code javascript qui fonctionne pour moi dans une situation similaire:
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) {
j'ai même cas avec vous, mais j'utilise une autre façon de s'authentifier.
j'ai un web et une api, tout cela pour les utilisateurs de l'intranet. Je n'utilise pas l'identité de l'utilisateur pour passer le web et l'api. Au lieu de cela, j'ai créé un compte web individuel, et chaque fois web utilisera ce compte spécial pour se connecter à l'api.
parce que, nous devons également nous assurer que les utilisateurs ne doivent pas se connecter directement à l'api. Ils ne doivent se connecter qu'à WEB ui.
Espérons que cette aide vous.
Voici une solution à votre problème. Vous pouvez utiliser Auth0 ici lien
L'utilisateur entre ses identifiants de connexion Le serveur vérifie les informations d'identification sont correctes et renvoie un jeton signé
ce jeton est stocké côté client, le plus souvent dans le stockage local - mais peut être stocké dans le stockage de session ou un cookie
les requêtes subséquentes au serveur incluent ce token comme un supplémentaire En-tête d'autorisation ou par l'une des autres méthodes mentionnés ci-dessus
le serveur décode le JWT et si le jeton est valide, il traite le demande
une fois qu'un utilisateur se déconnecte, le token est détruit côté client, non l'interaction avec le serveur est nécessaire
D'après vos commentaires ci-dessus, d'après ce que je comprends, vous avez un scénario dans lequel vous effectuez la connexion par le biais d'un navigateur, mais vous devez également invoquer les méthodes de l'api web en utilisant des appels ajax.
les appels du navigateur sont basés sur les cookies de session. Alors que les appels ajax du navigateur auraient le cookie de session dans l'en-tête, ce qui est requis est l'en-tête d'authentification qui doit être présent pour que l'api web puisse effectuer la validation.
Donc sur une connexion réussie, vous auriez également générer un le token basé sur l'api web, défini comme un cookie (qui est accessible par javascript) et puis pendant les appels ajax, récupérez-le à partir du cookie et incluez-le comme en-tête dans votre en-tête 'Authorization'.