我正在尝试创建一个AngularJs Web,它将登录名和密码发送到ASP.NET WebApi后端,并使用Thinktecture登录该用户。
我使用WS-Federation让Thinktecture与其他项目ASP.NET MVC一起正常工作。现在我正在尝试做类似的事情,但改变一些组件,我无法使它工作。
如何从ASP.NET WebApi将用户名和密码发送到Thinktecture并验证它?
using System.Collections.Generic;
using System.IdentityModel.Services;
using System.Web.Http;
using WebApi_AngularJs.Model;
namespace WebApi_AngularJs.Controllers
{
public class AuthorizationController : ApiController
{
// POST: api/Authorization
public LoginResponse Post([FromBody]Login data)
{
//HOW TO SEND data.user and data.password to ThinkTecture and get
//response if user valid or not??
var response = new LoginResponse { access_token = "token", data = "data"};
return response;
}
}
}
谢谢!
答案 0 :(得分:6)
您需要做一些事情。创建将生成令牌请求的OAuth客户端,并使用该客户端从身份服务器获取访问令牌,以允许您访问Web api端点。为此,您的OAuth客户端需要启用隐式流。然后,您通常会通过弹出窗口向Identity Server发出登录请求,以允许您的OAuth客户端登录。 您需要将登录请求的查询字符串中的OAuth客户端详细信息传递给Idsrv,OAuth客户端配置将是您在OAds客户端的Idsrv管理面板中定义的内容,您可以对其进行参数化并将其附加到oauth2 / authorzie网址:
getIdpOauthEndpointUrl: function () {
return "https://192.168.1.9/issue/oauth2/authorize";
},
getOAuthConfig: function () {
return {
client_id: "Your Oauth CLient ID that you specifie din Identity Server",
scope: "The scope of your RP",
response_type: "token",
redirect_uri: "https://..YourAngularAppUrl/AuthCallback.html"
};
}
然后打开登录窗口:
var url = authService.getIdpOauthEndpointUrl() + "?" + $.param(authService.getOAuthConfig());
window.open(url, "Login", "height=500,width=350");
在你的OAuth客户端inIdsrv中,你需要指定一个重定向网址,在我们的例子中:
https://YourAngularAppUrl/AuthCallback.html
这是您传递给身份服务器的登录请求以及OAuth客户端详细信息的内容。 AuthCallback.html
页面除了将查询字符串中的idsrv返回的访问令牌提取到该页面之外什么都不做,并将其传递到您的角度应用程序中,您如何做到这一点取决于您,但需要放置访问令牌进入$http
标题。
可以在AuthCallback.html页面中提取访问令牌,如下所示:
<script src="/Scripts/jquery-2.0.3.js"></script>
<script src="/Scripts/jquery.ba-bbq.min.js"></script>
<script type="text/javascript">
var params = $.deparam.fragment(location.hash.substring(1));
window.opener.oAuthCallback(params);
window.close();
</script>
OAuthCallback
函数在我的shell页面中定义,我的index.html负责将它给出的令牌传递到我的角度应用程序并将其放入$http
标题中。
function oAuthCallback(OAUTHTOKEN) {
angular.element(window.document).scope().setHttpAuthHeaderAndAuthenticate(OAUTHTOKEN);
}
我的setHttpAuthHeaderAndAuthenticate()
定义了$rootScope
函数,它将令牌放入$http
授权标题中:
$http.defaults.headers.common.Authorization = 'Bearer ' + OAUTHTOKEN["access_token"];
看看Christian Weyer的this post它正是我们正在做的事情,但它是一个淘汰/ web-api应用程序,同样的概念仍然存在。
下一步是告诉你的web api接受来自idsrv的访问令牌,这很简单;
public static void Configure(HttpConfiguration config)
{
var authConfig = new AuthenticationConfiguration();
authConfig.AddJsonWebToken(
YourIdsrvSiteId, YourRpsScope/Relam,YourRpsSymmetricSigningKey
);
config.MessageHandlers.Add(new AuthenticationHandler(authNConfig));
}
您还可以在此处定义ClaimsAuthenticationManager和ClaimsAuthorizationManager,以允许您转换声明并授予/拒绝访问web api资源。同样,这一切都在Christian Weyer的帖子中有所涉及。希望这会有所帮助。
答案 1 :(得分:5)
最后,在阅读了很多内容后,我有了这个:
在AngularJS中:
'use strict';
app.factory('authService', ['$http', '$q', 'localStorageService', function ($http, $q, localStorageService) {
var serviceBase = 'http://localhost:64346/';
var authServiceFactory = {};
var _authData = localStorageService.get('authorizationData');
var _authentication = {
isAuth: _authData != null? true : false,
userName: _authData != null ? _authData.userName : ""
};
var _saveRegistration = function (registration) {
_logOut();
return $http.post(serviceBase + 'api/account/register', registration).then(function (response) {
return response;
});
};
var _login = function (loginData) {
var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
var deferred = $q.defer();
$http.post(serviceBase + 'api/authorization', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) {
localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName });
_authentication.isAuth = true;
_authentication.userName = loginData.userName;
deferred.resolve(response);
}).error(function (err, status) {
_logOut();
deferred.reject(err);
});
return deferred.promise;
};
var _logOut = function () {
$http.delete(serviceBase + 'api/authorization').success(function() {
localStorageService.remove('authorizationData');
_authentication.isAuth = false;
_authentication.userName = "";
});
};
var _fillAuthData = function () {
var authData = localStorageService.get('authorizationData');
if (authData) {
_authentication.isAuth = true;
_authentication.userName = authData.userName;
}
}
authServiceFactory.saveRegistration = _saveRegistration;
authServiceFactory.login = _login;
authServiceFactory.logOut = _logOut;
authServiceFactory.fillAuthData = _fillAuthData;
authServiceFactory.authentication = _authentication;
return authServiceFactory;
}]);
在WebApi中:
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Protocols.WSTrust;
using System.IdentityModel.Services;
using System.IdentityModel.Tokens;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.Web.Http;
using System.Xml;
using Thinktecture.IdentityModel.Constants;
using Thinktecture.IdentityModel.WSTrust;
using WebApi_AngularJs.Model;
namespace WebApi_AngularJs.Controllers
{
public class AuthorizationController : ApiController
{
// GET: api/Authorization
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET: api/Authorization/5
[Authorize]
public string Get(int id)
{
return "value";
}
// POST: api/Authorization
public LoginResponse Post([FromBody]Login data)
{
var credentials = new ClientCredentials();
credentials.UserName.UserName = data.UserName;
credentials.UserName.Password = data.Password;
ServicePointManager.ServerCertificateValidationCallback = (obj, certificate, chain, errors) => true;
var claims = GetClaimsFromIdentityServer(data.UserName, data.Password);
var response = new LoginResponse();
if (claims != null)
{
//All set so now create a SessionSecurityToken
var token = new SessionSecurityToken(claims)
{
IsReferenceMode = true //this is
//important.this is how you say create
//the token in reference mode meaning
//your session cookie will contain only a
//referenceid(which is very small) and
//all claims will be stored on the server
};
FederatedAuthentication.WSFederationAuthenticationModule.
SetPrincipalAndWriteSessionToken(token, true);
response = new LoginResponse { access_token = token.Id , data = "data"};
}
return response;
}
// PUT: api/Authorization/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE: api/Authorization/
public void Delete()
{
//clear local cookie
FederatedAuthentication.SessionAuthenticationModule.SignOut();
FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie();
FederatedAuthentication.WSFederationAuthenticationModule.SignOut(false);
}
private ClaimsPrincipal GetClaimsFromIdentityServer(string username, string password)
{
const string WS_TRUST_END_POINT = "https://srv:4443/issue/wstrust/mixed/username";
var factory = new System.ServiceModel.Security.WSTrustChannelFactory
(new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
string.Format(WS_TRUST_END_POINT));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = username;
factory.Credentials.UserName.Password = password;
var rst = new System.IdentityModel.Protocols.WSTrust.RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
TokenType = TokenTypes.Saml2TokenProfile11,
AppliesTo = new EndpointReference
("urn:webapisecurity")
};
var st = factory.CreateChannel().Issue(rst);
var token = st as GenericXmlSecurityToken;
var handlers = FederatedAuthentication.FederationConfiguration.
IdentityConfiguration.SecurityTokenHandlers;
var token = handlers.ReadToken(new XmlTextReader
(new StringReader(token.TokenXml.OuterXml))) as Saml2SecurityToken;
var identity = handlers.ValidateToken(token).First();
var principal = new ClaimsPrincipal(identity);
return principal;
}
}
}
在Web.Config中:
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301879
-->
<configuration>
<configSections>
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="ida:FederationMetadataLocation" value="https://srv:4443/FederationMetadata/2007-06/FederationMetadata.xml" />
<add key="ida:Realm" value="urn:webapisecurity" />
<add key="ida:AudienceUri" value="urn:webapisecurity" />
<add key="AppName" value="Web API Security Sample" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<modules>
<add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
</modules>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
<system.identityModel>
<identityConfiguration>
<audienceUris>
<add value="urn:webapisecurity" />
</audienceUris>
<claimsAuthorizationManager type="Thinktecture.IdentityServer.Ofi.AuthorizationManager, Thinktecture.IdentityServer.Ofi, Version=1.0.0.0, Culture=neutral" />
<claimsAuthenticationManager type="Thinktecture.IdentityServer.Ofi.AuthenticationManager, Thinktecture.IdentityServer.Ofi, Version=1.0.0.0, Culture=neutral" />
<certificateValidation certificateValidationMode="None" />
<issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<trustedIssuers>
<add thumbprint="489116B0FCF14DF66D47AE272C3B9FD867D0E050" />
</trustedIssuers>
</issuerNameRegistry>
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler requireSsl="false" />
<wsFederation passiveRedirectEnabled="true" issuer="https://srv:4443/issue/wsfed" realm="urn:webapisecurity" reply="http://localhost:64346/" requireHttps="false" />
</federationConfiguration>
</system.identityModel.services>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
有了这个,我可以看到在浏览器中设置了FedAuth cookie,它也在WebApi中进行验证。