我创建了一个托管在Azure上的MVC 5 Web应用程序和一个WPF客户端。我的短期目的(好像我可以实现我能够实现我的所有用例)如下:
我的实际问题如下: 用户启动应用程序,并提示进行身份验证。我想它可以工作,因为我可以显示用户的邮件,我有一个访问令牌。 用户尝试访问web api控制器,它工作正常 用户试图访问另一个用[Authorize]修饰的web api控制器,我得到一些HTML页面,说明:“我们无法登录你。你的浏览器目前设置为阻止JavaScript。你需要允许JavaScript使用这项服务。“
从我在网上搜索到的内容看来,它可能与我的网络应用程序配置不正确(我已经尝试在受信任的网站中添加我的webapp网址,我确信我的控制器网址好的)。我在本机客户端+ AAD + MVC上找不到太多doc,所以我真的不知道如何纠正它。
这是我在webapp上的startup.auth.cs:
public partial class Startup
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string appKey = ConfigurationManager.AppSettings["ida:AppKey"];
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
private static string tenantId = ConfigurationManager.AppSettings["ida:TenantId"];
private static string postLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"];
private static string certName = ConfigurationManager.AppSettings["ida:CertName"];
public static readonly string Authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
string graphResourceId = ConfigurationManager.AppSettings["ida:GraphUrl"];
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = Authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
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;
#region Certs (not used)
if (certName.Length != 0)
{
// Create a Client Credential Using a Certificate
//
// Initialize the Certificate Credential to be used by ADAL.
// First find the matching certificate in the cert store.
//
X509Certificate2 cert = null;
X509Store store = new X509Store(StoreLocation.CurrentUser);
try
{
store.Open(OpenFlags.ReadOnly);
// Place all certificates in an X509Certificate2Collection object.
X509Certificate2Collection certCollection = store.Certificates;
// Find unexpired certificates.
X509Certificate2Collection currentCerts = certCollection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
// From the collection of unexpired certificates, find the ones with the correct name.
X509Certificate2Collection signingCert = currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certName, false);
if (signingCert.Count == 0)
{
// No matching certificate found.
return Task.FromResult(0);
}
// Return the first certificate in the collection, has the right name and is current.
cert = signingCert[0];
}
finally
{
store.Close();
}
// Then create the certificate credential.
ClientAssertionCertificate credential = new ClientAssertionCertificate(clientId, cert);
string userObjectID = context.AuthenticationTicket.Identity.FindFirst(
"http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceId);
AuthenticationHelper.token = result.AccessToken;
}
#endregion
else
{
// Create a Client Credential Using an Application Key
ClientCredential credential = new ClientCredential(clientId, appKey);
string userObjectID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceId);
AuthenticationHelper.token = result.AccessToken;
}
return Task.FromResult(0);
}
}
});
}
}
这是在没有[Authorize]修饰的情况下可以加入的控制器,但是在这种情况下,动作抛出一个空异常(但是如果我不能修复它,我会发布另一个问题):
[System.Web.Http.Authorize]
public class UserADGraphController : ApiController
{
[ResponseType(typeof(IUser))]
[System.Web.Http.Route("api/UserADGraphController/GetMyInformations")]
public IHttpActionResult GetMyInformations()
{
try
{
string uID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
if (uID == null)
return Ok("UId null");
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
if (client == null)
return Ok("Client null");
IUser adUser = client.Users.Where(u => u.ObjectId == uID).ExecuteAsync().Result.CurrentPage.SingleOrDefault();
if (adUser == null)
{
return NotFound();
}
return Ok(adUser);
}
catch (Exception e)
{
return Ok(e.Message + " " + e.StackTrace);
}
最后这里是客户的相关部分:
在mainviewmodel类中:
#region Azure AD auth properties
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
Uri redirectUri = new Uri(ConfigurationManager.AppSettings["ida:RedirectUri"]);
private static string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
private static string AppServiceResourceId = ConfigurationManager.AppSettings["todo:AppServiceResourceId"];
private static string AppServiceBaseAddress = ConfigurationManager.AppSettings["todo:AppServiceBaseAddress"];
private HttpClient httpClient;
private AuthenticationContext authContext = null;
#endregion
在mainviewmodel构造函数中:
authContext = new AuthenticationContext(authority);
httpClient = new HttpClient();
我的登录方法:
{
AuthenticationResult result = null;
try
{
result = authContext.AcquireToken(AppServiceResourceId, clientId, redirectUri, PromptBehavior.Auto);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
SignInLabelContent = "Connected to azure AD as " + result.UserInfo.DisplayableId;
}
catch (AdalException ex)
{
if (ex.ErrorCode == "user_interaction_required")
{
}
else
{
// An unexpected error occurred.
string message = ex.Message;
if (ex.InnerException != null)
{
message += "Inner Exception : " + ex.InnerException.Message;
}
Messenger.Default.Send<NotificationMessage>(new NotificationMessage(message));
//MessageBox.Show(message);
}
return;
}
}
访问受保护控制器的方法:
IUser me = null;
AuthenticationResult result = null;
result = authContext.AcquireToken(AppServiceResourceId, clientId, redirectUri, PromptBehavior.Auto);
string authHeader = result.CreateAuthorizationHeader();
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
//HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, AppServiceBaseAddress + "/api/UserADGraphController/GetMyInformations");
//request.Headers.TryAddWithoutValidation("Authorization", authHeader);
//HttpResponseMessage response = await client.SendAsync(request);
//string responseString = await response.Content.ReadAsStringAsync();
//LogManager.log(responseString);
//Messenger.Default.Send<NotificationMessage>(new NotificationMessage(responseString));
HttpResponseMessage response = await httpClient.GetAsync(AppServiceBaseAddress + "/api/UserADGraphController/GetMyInformations");
if (response.IsSuccessStatusCode)
{
var jsonString = await response.Content.ReadAsStringAsync();
LogManager.log(jsonString);
me = JsonConvert.DeserializeObject<IUser>(jsonString);
//Messenger.Default.Send<NotificationMessage>(new NotificationMessage(jsonString));
}
在我的情况下,响应的状态代码为200,但是jsonString包含告诉我有关禁用javascript的网页。
如果有人有想法那就太棒了!
谢谢!
答案 0 :(得分:0)
如果有人遇到此问题,我设法通过以这种方式更改我的configureAuth方法来解决它:
var azureADBearerAuthOptions = new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = tenant
};
azureADBearerAuthOptions.TokenValidationParameters = new TokenValidationParameters()
{
ValidAudience = audience
};
app.UseWindowsAzureActiveDirectoryBearerAuthentication(azureADBearerAuthOptions);
答案 1 :(得分:0)
此错误消息非常具有误导性。我遇到了同样的问题,发现我的问题实际上与Client Secret / AppURI设置不匹配。
从错误消息中,我认为这是我在ConfigureAuth方法中所做的事情。事实证明我正在混合开发和测试设置。
也许这会帮助那些最终出现这个令人困惑的错误消息的人。