这几天我一直在摆弄这个…
我想做的是用Azure AD认证用户,成功时,使用ASP自动登录他们。. NET标识用于授权。如果他们没有帐户,我想自动创建一个。
本质上Azure AD只是确认他们是组织的一部分,ASP。. NET身份部分是它自己的数据库,我可以使用[Authorize]
属性在Azure AD之外设置自定义角色。
这是我的ConfigureAuth()
方法:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(IntranetApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = SettingsHelper.ClientId,
Authority = SettingsHelper.Authority,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
// If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey);
String signInUserId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(signInUserId));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, SettingsHelper.AADGraphResourceId);
return Task.FromResult(0);
},
RedirectToIdentityProvider = (context) =>
{
// This ensures that the address used for sign in and sign out is picked up dynamically from the request
// this allows you to deploy your app (to Azure Web Sites, for example)without having to change settings
// Remember that the base URL of the address used here must be provisioned in Azure AD beforehand.
string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl + "/";
context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
return Task.FromResult(0);
},
AuthenticationFailed = (context) =>
{
// Suppress the exception if you don't want to see the error
context.HandleResponse();
return Task.FromResult(0);
}
}
});
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
},
});
}
现在ASP。. NET身份接管时,我做一个HttpContext.Request.IsAuthenticated
这是可以的,我只需要一种方法来检查OpenID部分是否经过身份验证或不,所以我可以把我的自定义逻辑自动登录用户
明白了!
我最大的问题是试图使用OWIN中间件为我做所有的事情。OpenID中间件不需要用于Azure AD的简单身份验证。我基本上在Account控制器中创建了一个OpenIdAuth
方法,它充当我的中间人,在用户访问站点之前使用Azure对其进行身份验证。
[AllowAnonymous]
public ActionResult OpenIdAuth(string code)
{
string clientId = "00000000-0000-0000-0000-000000000000"; // Client ID found in the Azure AD Application
string appKey = "111111111112222222222223333333333AAABBBCCC="; // Key generated in the Azure AD Appliction
if (code != null)
{
string commonAuthority = "https://login.windows.net/<TENANT_URL>"; // Eg. https://login.windows.net/MyDevSite.onmicrosoft.com
var authContext = new AuthenticationContext(commonAuthority);
ClientCredential credential = new ClientCredential(clientId, appKey);
AuthenticationResult authenticationResult = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Request.Url.GetLeftPart(UriPartial.Path)), credential, "https://graph.windows.net");
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
var user = UserManager.FindByName(authenticationResult.UserInfo.UniqueId);
if (user != null)
{
signInManager.SignIn(user, false, false);
}
else
{
var newUser = new ApplicationUser { UserName = authenticationResult.UserInfo.UniqueId, Email = authenticationResult.UserInfo.DisplayableId };
var creationResult = UserManager.Create(newUser);
if (creationResult.Succeeded)
{
user = UserManager.FindByName(newUser.UserName);
signInManager.SignIn(user, false, false);
}
else
{
return new ViewResult { ViewName = "Error" };
}
}
return Redirect("/");
}
else
{
var url = new Uri($"https://login.microsoftonline.com/<TENANT_URL>/oauth2/authorize?client_id={clientId}&response_type=code&redirect_uri=https://localhost/Account/OpenIdAuth");
return Redirect(url.AbsoluteUri);
}
}
最棒的部分是code
变量,它将在用户成功登录时由Microsoft传递。我使用相同的控制器方法并检查它是否为null,但技术上可以使用两种不同的控制器方法(Microsoft将重定向回您为redirect_uri
参数指定的url)。
在我得到授权码后,我可以使用Microsoft.IdentityModel.Clients.ActiveDirectory
nuget包中的AuthorizationContext
来调用:AcquireTokenByAuthorizationCode
。最后一个参数是Resource URI。我正在使用图形资源,但你可以使用任何其他资源,你已经给你的应用程序访问Azure管理门户。
最后,我的ConfigureAuth
方法回到了普通的老式ASP。. NET标识版本:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(IntranetApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
},
});
}