ASP.NET (OWIN)
配置Authok
获取应用密钥
你需要如下信息
- Domain
- Client ID
- Client Secret
配置回调URL
配置 Logout URL
集成 Authok
安装 OpenID Connect 中间件
Install-Package Microsoft.Owin.Security.OpenIdConnect
下面的中间件用于开启cookie认证:
Install-Package Microsoft.Owin.Security.Cookies
在Startup
类的 Configuration
方法中配置 cookie中间件 和 Authok 中间件:
Startup.cs
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin;
using Microsoft.Owin.Host.SystemWeb;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using MvcApplication.Support;
using Owin;
public void Configuration(IAppBuilder app)
{
// Configure Authok parameters
string authokDomain = ConfigurationManager.AppSettings["authok:Domain"];
string authokClientId = ConfigurationManager.AppSettings["authok:ClientId"];
string authokRedirectUri = ConfigurationManager.AppSettings["authok:RedirectUri"];
string authokPostLogoutRedirectUri = ConfigurationManager.AppSettings["authok:PostLogoutRedirectUri"];
// Set Cookies as default authentication type
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
LoginPath = new PathString("/Account/Login"),
// Configure SameSite as needed for your app. Lax works well for most scenarios here but
// you may want to set SameSiteMode.None for HTTPS
CookieSameSite = SameSiteMode.Lax,
// More information on why the CookieManager needs to be set can be found here:
// https://github.com/aspnet/AspNetKatana/wiki/System.Web-response-cookie-integration-issues
CookieManager = new SameSiteCookieManager(new SystemWebCookieManager())
});
// Configure Authok authentication
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "Authok",
Authority = $"https://{authokDomain}",
ClientId = authokClientId,
RedirectUri = authokRedirectUri,
PostLogoutRedirectUri = authokPostLogoutRedirectUri,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name"
},
// More information on why the CookieManager needs to be set can be found here:
// https://docs.microsoft.com/en-us/aspnet/samesite/owin-samesite
CookieManager = new SameSiteCookieManager(new SystemWebCookieManager()),
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = notification =>
{
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
var logoutUri = $"https://{authokDomain}/v1/logout?client_id={authokClientId}";
var postLogoutUri = notification.ProtocolMessage.PostLogoutRedirectUri;
if (!string.IsNullOrEmpty(postLogoutUri))
{
if (postLogoutUri.StartsWith("/"))
{
// transform to absolute
var request = notification.Request;
postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
}
logoutUri += $"&returnTo={ Uri.EscapeDataString(postLogoutUri)}";
}
notification.Response.Redirect(logoutUri);
notification.HandleResponse();
}
return Task.FromResult(0);
}
}
});
}
触发认证
添加登录和退登方法
在AccountController
中添加Login
和Logout
方法.
Login
方法将会委托 OpenID Connect 中间件来启动认证流程.Logout
方法将会把用户从cookie中间件和 OpenID Connect 中间件中注销(将会清空本地应用会话):Controllers/AccountController.cs
public class AccountController : Controller
{
public ActionResult Login(string returnUrl)
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties
{
RedirectUri = returnUrl ?? Url.Action("Index", "Home")
},
"Authok");
return new HttpUnauthorizedResult();
}
[Authorize]
public void Logout()
{
HttpContext.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
HttpContext.GetOwinContext().Authentication.SignOut("Authok");
}
[Authorize]
public ActionResult Claims()
{
return View();
}
}
添加登录和注销链接
在导航栏添加 登录,注销 链接.
Views/Shared/_Layout.cshtml
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
</ul>
<ul class="nav navbar-nav navbar-right">
@if (User.Identity.IsAuthenticated)
{
<li>@Html.ActionLink("Logout", "Logout", "Account")</li>
}
else
{
<li>@Html.ActionLink("Login", "Login", "Account")</li>
}
</ul>
</div>
</div>
</div>
调用API获取 Access Token
通过传递 audience 参数和 API的identifier给Authok的授权端点,来获取 Access Token.
你需要配置 OpenID Connect 中间件,添加 ID Token 和 Access Token 声明到 ClaimsIdentity
.
在Startup
中更新 OpenID Connect中间件的配置:
- 设置
ResponseType
为OpenIdConnectResponseType.Code
. OpenID Connect中间件会提取 Access Token并存储到ProtocolMessage
. - 设置
RedeemCode
为true
. - 设置
ClientSecret
为应用的Client Secret. - 实现
RedirectToIdentityProvider
以追加audience
参数. - 实现
SecurityTokenValidated
,从ProtocolMessage
中提取 ID Token 和 Access Token.
Startup.cs
public void Configuration(IAppBuilder app)
{
// Some code omitted for brevity...
string authokClientSecret = ConfigurationManager.AppSettings["authok:ClientSecret"];
string authokAudience = ConfigurationManager.AppSettings["authok:Audience"];
// Configure Authok authentication
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
//...
ClientSecret = authokClientSecret,
ResponseType = OpenIdConnectResponseType.Code,
RedeemCode = true,
//...
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = notification =>
{
notification.AuthenticationTicket.Identity.AddClaim(new Claim("id_token", notification.ProtocolMessage.IdToken));
notification.AuthenticationTicket.Identity.AddClaim(new Claim("access_token", notification.ProtocolMessage.AccessToken));
return Task.FromResult(0);
},
RedirectToIdentityProvider = notification =>
{
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
{
// The context's ProtocolMessage can be used to pass along additional query parameters
// to Authok's /authorize endpoint.
//
// Set the audience query parameter to the API identifier to ensure the returned Access Tokens can be used
// to call protected endpoints on the corresponding API.
notification.ProtocolMessage.SetParameter("audience", authokAudience);
}
else if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
//...
}
return Task.FromResult(0);
}
}
});
}
对应的 web.config 配置:
web.config
<configuration>
<appSettings>
<add key="authok:ClientSecret" value="{CLIENT_SECRET}" />
<add key="authok:Audience" value="{API_IDENTIFIER}" />
</appSettings>
</configuration>
Controllers/AccountController.cs
[Authorize]
public ActionResult Tokens()
{
var claimsIdentity = User.Identity as ClaimsIdentity;
// Extract tokens
string accessToken = claimsIdentity?.FindFirst(c => c.Type == "access_token")?.Value;
string idToken = claimsIdentity?.FindFirst(c => c.Type == "id_token")?.Value;
// Now you can use the tokens as appropriate...
}