Skip to main content

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中添加LoginLogout方法.

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中间件的配置:

  1. 设置ResponseTypeOpenIdConnectResponseType.Code. OpenID Connect中间件会提取 Access Token并存储到ProtocolMessage.
  2. 设置RedeemCodetrue.
  3. 设置ClientSecret为应用的Client Secret.
  4. 实现RedirectToIdentityProvider以追加audience参数.
  5. 实现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...
}