我一直在尝试在我们的 .Net 4.5.2 网站项目中实施一个可行的解决方案。 我的目标是将我的网站项目(一个 Web 表单应用程序(不是 MVC))转换为使用身份服务器 3(可能通过 thinktecture 的实现)来验证/授权用户。
这可能吗? 站点生命周期将如何变化,或者它可以对会话对象说同样的话?我可以使用身份服务器获取访问令牌然后设置会话,并且仅在会话到期或访问令牌到期时请求新的访问令牌吗?
一些背景故事:
我在以下位置https://localhost:44399确实有一个有效的身份服务器 3 设置。当我使用直接的 html 文件时,它会响应所有适当的调用和限制,但是当我尝试在登录页面 (portal.aspx) 中实现相同的东西时,它似乎忘记了用户并且行为不一样。该网站(客户端)设置在https://localhost:9898上。登录页面是https://localhost:9898/portal.aspx。
我在 portal.aspx 页面上使用了 oidc-client.js,但是当它尝试进行身份验证时,我不断收到 CORS(跨浏览器源脚本)错误。 这是 Web 表单的问题吗?使用常规 html 页面时不会发生这种情况?
这是一个 .net 4.5.2 “网站项目”(不是“网络应用程序项目”),它使用 Web 表单,而不是 MVC。我有许多演示 MVC 应用程序可以正常工作,但是当我尝试将我所拥有的知识用于 Web 表单应用程序时,我发现我真的不了解正在发生的事情。
我添加了以下 nuget 包:
Microsoft.Bcl v1.1.10
Microsoft.Owin v3.0.1
Microsoft.Bcl.Async v1.0.168
System.IdentityModel.Tokens.Jwt v5.1.0
Newtonsoft.Json v9.0.1
Owin v1.0.0
Microsoft.IdentityModel.Logging v1.1.0
Microsoft.Owin.Host.SystemWeb v3.0.1
System.IdentityModel.Tokens.Jwt v5.1.0
Microsoft.IdentityModel.Tokens v5.1.0
Microsoft.Bcl.Build v1.0.21
Thinktecture.IdentityModel v3.6.1
当我尝试添加 startup.cs 类时,它告诉我这些类通常添加到 App_Code 目录中,我想把它放在那里吗?我已经尝试过 root 和 App_Code 目录,但在调用它们时似乎都没有注册。我已经添加了包,认为这就是调用的内容:
Microsoft.Owin.Host.SystemWeb
但似乎启动类没有注册。 那么我如何让它在管道中注册,以便 401 未授权错误将用户发送到身份服务器?
这是我的启动课:
using ExpenseTracker.WebClient.Helpers;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Newtonsoft.Json.Linq;
using Owin;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Web;
using System.Web.Helpers;
using Thinktecture.IdentityModel.Client;
[assembly: OwinStartup(typeof(ExpenseTracker.WebClient.Startup))]
namespace ExpenseTracker.WebClient
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
AntiForgeryConfig.UniqueClaimTypeIdentifier = "unique_user_key";
app.UseResourceAuthorization(new AuthorizationManager());
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = "mvc",
Authority = ExpenseTrackerConstants.IdSrv,
RedirectUri = ExpenseTrackerConstants.ExpenseTrackerClient,
SignInAsAuthenticationType = "Cookies",
ResponseType = "code id_token token",
Scope = "openid profile roles expensetrackerapi offline_access",
Notifications = new OpenIdConnectAuthenticationNotifications()
{
MessageReceived = async n =>
{
EndpointAndTokenHelper.DecodeAndWrite(n.ProtocolMessage.IdToken);
EndpointAndTokenHelper.DecodeAndWrite(n.ProtocolMessage.AccessToken);
//var userInfo = await EndpointAndTokenHelper.CallUserInfoEndpoint(n.ProtocolMessage.AccessToken);
},
SecurityTokenValidated = async n =>
{
var userInfo = await EndpointAndTokenHelper.CallUserInfoEndpoint(n.ProtocolMessage.AccessToken);
// use the authorization code to get a refresh token
var tokenEndpointClient = new OAuth2Client(
new Uri(ExpenseTrackerConstants.IdSrvToken),
"mvc", "secret");
var tokenResponse = await tokenEndpointClient.RequestAuthorizationCodeAsync(
n.ProtocolMessage.Code, ExpenseTrackerConstants.ExpenseTrackerClient);
var givenNameClaim = new Claim(
Thinktecture.IdentityModel.Client.JwtClaimTypes.GivenName,
userInfo.Value<string>("given_name"));
var familyNameClaim = new Claim(
Thinktecture.IdentityModel.Client.JwtClaimTypes.FamilyName,
userInfo.Value<string>("family_name"));
var roles = userInfo.Value<JArray>("role").ToList();
var newIdentity = new ClaimsIdentity(
n.AuthenticationTicket.Identity.AuthenticationType,
Thinktecture.IdentityModel.Client.JwtClaimTypes.GivenName,
Thinktecture.IdentityModel.Client.JwtClaimTypes.Role);
newIdentity.AddClaim(givenNameClaim);
newIdentity.AddClaim(familyNameClaim);
foreach (var role in roles)
{
newIdentity.AddClaim(new Claim(
Thinktecture.IdentityModel.Client.JwtClaimTypes.Role,
role.ToString()));
}
var issuerClaim = n.AuthenticationTicket.Identity
.FindFirst(Thinktecture.IdentityModel.Client.JwtClaimTypes.Issuer);
var subjectClaim = n.AuthenticationTicket.Identity
.FindFirst(Thinktecture.IdentityModel.Client.JwtClaimTypes.Subject);
newIdentity.AddClaim(new Claim("unique_user_key",
issuerClaim.Value + "_" + subjectClaim.Value));
newIdentity.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
newIdentity.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
newIdentity.AddClaim(new Claim("expires_at",
DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
n.AuthenticationTicket = new AuthenticationTicket(
newIdentity,
n.AuthenticationTicket.Properties);
},
}
});
}
}
}
更糟糕的是,添加 Microsoft.Owin.Host.SystemWeb 由于以下奇怪的错误而无法编译:
The type or namespace name 'SessionState' does not exist in the
namespace 'System.Web' (are you missing an assembly reference?)