SimpleMembership dans MVC4 app + WebApi l'aide de la base HTTP auth
Je suis en train de mettre en œuvre un MVC4 application web avec les exigences suivantes:
(a), il offre ses services à des utilisateurs authentifiés uniquement. Comme pour l'authentification, j'aimerais utiliser de simples membres, comme c'est la dernière technique d'authentification de MVC, me donne l'avantage de définir ma propre db tables, fournit OAuth soutien hors de la boîte, et s'intègre facilement avec les deux MVC et WebApi.
(b) il expose certaines fonctions de base via WebApi pour mobile/JS clients, qui devrait être authentifié à l'aide d'authentification HTTP de base (+SSL). Généralement je vais avoir JS clients à l'aide de jQuery AJAX appels à WebApi contrôleurs, décoré avec les Autoriser attribut pour les différents rôles de l'utilisateur.
(c) dans l'idéal, dans un environnement mixte, je voudrais éviter une double authentification: c'est à dire si l'utilisateur est déjà authentifié via un navigateur, et est de visiter une page, ce qui implique un JS appel à un WebApi d'action du contrôleur, le (a) mécanisme devrait être suffisant.
Ainsi, alors que (un) est couvert par le défaut MVC modèle, (b) requiert une authentification HTTP basique sans la médiation d'un navigateur. À cette fin, je doit créer un DelegatingHandler comme celle que j'ai trouvé dans ce post: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers.
Le problème est que sa mise en œuvre requiert une certaine façon de la récupération d'un IPrincipal de la reçu le nom d'utilisateur et le mot de passe, et le WebSecurity classe ne fournit pas de méthode pour cela (à l'exception de la Connexion, mais je voudrais éviter de changer l'utilisateur juste pour les fins de l'autorisation, également à cause du potentiel "mixte" des environnements tels que (c)). Il semble donc ma seule option est de donner aux simples membres. Quelqu'un aurait-il une meilleure suggestions? Voici la (légèrement modifié) le code de la cité de poste:
public interface IPrincipalProvider
{
IPrincipal GetPrincipal(string username, string password);
}
public sealed class Credentials
{
public string Username { get; set; }
public string Password { get; set; }
}
public class BasicAuthMessageHandler : DelegatingHandler
{
private const string BasicAuthResponseHeader = "WWW-Authenticate";
private const string BasicAuthResponseHeaderValue = "Basic";
public IPrincipalProvider PrincipalProvider { get; private set; }
public BasicAuthMessageHandler(IPrincipalProvider provider)
{
if (provider == null) throw new ArgumentNullException("provider");
PrincipalProvider = provider;
}
private static Credentials ParseAuthorizationHeader(string sHeader)
{
string[] credentials = Encoding.ASCII.GetString(
Convert.FromBase64String(sHeader)).Split(new[] { ':' });
if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) ||
String.IsNullOrEmpty(credentials[1])) return null;
return new Credentials
{
Username = credentials[0],
Password = credentials[1],
};
}
protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
AuthenticationHeaderValue authValue = request.Headers.Authorization;
if (authValue != null && !String.IsNullOrWhiteSpace(authValue.Parameter))
{
Credentials parsedCredentials = ParseAuthorizationHeader(authValue.Parameter);
if (parsedCredentials != null)
{
Thread.CurrentPrincipal = PrincipalProvider
.GetPrincipal(parsedCredentials.Username, parsedCredentials.Password);
}
}
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
if (response.StatusCode == HttpStatusCode.Unauthorized
&& !response.Headers.Contains(BasicAuthResponseHeader))
{
response.Headers.Add(BasicAuthResponseHeader,
BasicAuthResponseHeaderValue);
}
return response;
});
}
}
OriginalL'auteur Naftis | 2013-02-11
Vous devez vous connecter pour publier un commentaire.
Voici une autre solution qui répond à toutes vos exigences. Il utilise SimpleMemberhsip avec un mélange de formes d'authentification et de l'authentification de base dans une application MVC 4. Il peut également l'appui de l'Autorisation, mais il n'est pas nécessaire en laissant le Rôle de la propriété null.
OriginalL'auteur Kevin Junghans
Merci, cela semble la meilleure solution disponible à cette heure!
J'ai réussi à créer une fausse solution à partir de zéro (le trouver ici: http://sdrv.ms/YpkRcf ), et il semble fonctionner dans les cas suivants:
1) lorsque j'essaie d'accéder à un contrôleur MVC restreint d'action, je suis redirigé vers la page de connexion, comme prévu, à obtenir authentifié.
2) lorsque j'déclencher un jQuery ajax appel à un WebApi contrôleur restreint d'action, l'appel aboutit (sauf bien sûr quand on n'utilise pas SSL).
Encore, il ne fonctionne pas lorsque après l'ouverture de session dans le site web, les appels de l'API toujours requiert une authentification. Quelqu'un pourrait-il expliquer ce qu'il se passe ici? Dans ce qui suit, je détail mon intervention car je pense que cela pourrait être utile pour les débutants comme moi.
Merci (désolé pour la mise en forme de ce qui suit, mais je n'arrive pas à laisser de cet éditeur mark code en conséquence...)
Procédure
créer un nouveau mvc4 application (base mvc4 application: c'est déjà fourni avec universal fournisseurs. Toutes les universels fournisseurs de noms de classes commencent par Défaut...);
personnaliser web.config pour votre non-local DB, par exemple:
Aussi il est souvent utile de définir un machineKey pour le hachage des mots de passe, de sorte que vous pouvez déplacer librement ce site autour de serveur à serveur, sans avoir vos mots de passe codé. Utiliser une machine clé de générateur de site web pour définir une entrée comme celle-ci:
si nécessaire, créez une nouvelle base de données vide correspondant à la chaîne de connexion de votre site web.config. Puis commencer notre bon vieux pote WSAT (VS Projet de menu) et configurer la sécurité par l'ajout d'utilisateurs et de rôles en tant que de besoin.
si vous le souhaitez, ajouter un contrôleur HomeController avec un Indice d'action, car aucun contrôleur n'est présent dans ce modèle, et donc vous ne pourriez pas l'essai de démarrage de votre application web sans elle.
ajouter Thinktecture.IdentityModel.45 à partir de NuGet et ajouter/mettre à jour tous vos favori packages NuGet. Notez bien qu'au moment de l'écriture, jquery validation discrète à partir de MS n'est pas plus compatible avec jQuery 1.9 ou plus. J'ai plutôt l'utilisation d' http://plugins.jquery.com/winf.unobtrusive-ajax/ . Donc, supprimer jquery.discrète* et ajouter cette bibliothèque (qui se compose de winf.discrète-ajax et autres méthodes) dans votre faisceaux (App_Start/BundleConfig.cs).
modifier le WebApiConfig.cs dans App_Start par l'ajout du code après la DefaultApi route de configuration:
public static de la classe WebApiConfig
{
public static void Enregistrer(HttpConfiguration config)
{
config.Les itinéraires.MapHttpRoute(
nom: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
valeurs par défaut: new { id = RouteParameter.Facultatif }
);
}
Être plus propre, l'api contrôleurs sera placé sous Contrôleurs/Api/, donc créer ce dossier.
Ajouter aux modèles une LoginModel.cs:
public class LoginModel
{
[Obligatoire]
[Display(Name = "nom d'utilisateur", ResourceType = typeof(StringResources))]
public string nom d'utilisateur { get; set; }
}
Ce modèle requiert un StringResources.resx de ressources (avec génération de code) j'ai l'habitude de placer sous un dossier des Actifs, avec les 3 chaînes de cité dans les attributs.
Ajouter un ClaimsTransformer.cs à votre solution de racine, comme ceci:
public class ClaimsTransformer : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authentifier(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (!incomingPrincipal.L'identité.IsAuthenticated)
{
de retour de la base.Authentifier(resourceName, incomingPrincipal);
}
}
Ajouter Application_PostAuthenticateRequest Global.asax.cs:
public class MvcApplication : HttpApplication
{
...
protected void Application_PostAuthenticateRequest()
{
si (ClaimsPrincipal.Actuel.L'identité.IsAuthenticated)
{
var transformateur = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
var newPrincipal = transformateur.Authentifier(chaîne de caractères.Vide, ClaimsPrincipal.Actuel);
}
web.config (remplacer YourAppNamespace avec votre application espace de noms racine):
<configSections>
<section name="le système de.identityModel"
type="System.IdentityModel.La Configuration.SystemIdentityModelSection, Système.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
...
ajouter les autres modèles pour le compte du contrôleur, avec leur point de vue (vous pouvez les déduire de MVC3 modèle d'application, même si je préfère les changer plus localisable-amicale des variantes à l'aide d'attributs nécessitant une ressource de chaîne des noms plutôt que des littéraux).
pour tester l'authentification basée sur navigateur, ajouter un peu de [Autorisé] action d'un contrôleur (par exemple HomeController), et essayez d'accéder.
pour tester l'authentification HTTP de base, insérez dans certains (par exemple Home/Index) un code comme ceci (à définir votre nom d'utilisateur et le mot de passe dans la variable du jeton):
...
<p>appel d'Essai
$(function() {
$("#test").cliquez sur(function () {
var token = "nom d'utilisateur:MOT de passe";
var hash = $.base64.coder(token);
var-tête = "Base" + de hachage;
console.journal(en-tête);
Cela nécessite le plugin jQuery pour l'encodage/décodage en Base64: jquery.base64.js et son minifiés homologue.
À autoriser SSL, suivez les instructions ici: http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx (en gros, activer le SSL dans le web propriétés du projet et de se connecter au port spécifié dans la valeur de la propriété).
OriginalL'auteur Naftis
Peut-être cela permet - sons c'est comme votre scénario:
http://leastprivilege.com/2012/10/23/mixing-mvc-forms-authentication-and-web-api-basic-authentication/
http://leastprivilege.com/2012/10/24/extensions-to-the-web-apimvc-formsbasic-auth-sample-claims-transformation-and-ajax/
OriginalL'auteur leastprivilege