Alexa技能和Azure AD身份验证
问题描述:
我正在尝试构建连接到使用Azure AD身份验证的企业应用程序的alexa技能。我们在本文中设置了一切,如https://blogs.msdn.microsoft.com/premier_developer/2016/12/12/amazon-alexa-skills-development-with-azure-active-directory-and-asp-net-core-1-0-web-api/,但我在将标记从请求正文移动到标题时遇到问题。 请求通过罚款,我可以解析它,我将标记添加到标题,但在亚马逊的测试页上我得到此消息:“有一个错误调用远程端点,它返回HTTP 302:找到”Alexa技能和Azure AD身份验证
这是添加的令牌发送给报头的代码:
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.Use(async (context, next) =>
{
string path = string.Format(ConfigurationManager.AppSettings["ExchangeTraceDrivePath"], "AlexaRequest", DateTime.Now.ToFileTime(), "");
var stream = context.Request.Body;
try
{
using (var buffer = new MemoryStream())
{
await stream.CopyToAsync(buffer);
var bodyBuffer = new byte[buffer.Length];
buffer.Position = 0L;
buffer.Read(bodyBuffer, 0, bodyBuffer.Length);
var body = Encoding.UTF8.GetString(bodyBuffer);
using (var sw = new StreamWriter(path))
{
sw.WriteLine(DateTime.Now.ToString() + " body: " + body);
sw.WriteLine("---------------------------------------------------------------------------------------------");
foreach (var header in context.Request.Headers)
{
sw.WriteLine(DateTime.Now.ToString() + " header key: " + header.Key);
foreach (var val in header.Value)
{
sw.WriteLine(DateTime.Now.ToString() + " header value: " + val);
}
}
sw.WriteLine("---------------------------------------------------------------------------------------------");
dynamic json = JObject.Parse(body);
sw.WriteLine(DateTime.Now.ToString() + " parsed body: " + json);
sw.WriteLine("---------------------------------------------------------------------------------------------");
if (json?.session?.user?.accessToken != null)
{
sw.WriteLine(DateTime.Now.ToString() + " access accessToken found " +
json?.session?.user?.accessToken);
sw.WriteLine("---------------------------------------------------------------------------------------------");
context.Request.Headers.Add("Authorization",
new string[] { string.Format("Bearer {0}", json?.session?.user?.accessToken) });
foreach (var header in context.Request.Headers)
{
sw.WriteLine(DateTime.Now.ToString() + " header key: " + header.Key);
foreach (var val in header.Value)
{
sw.WriteLine(DateTime.Now.ToString() + " header value: " + val);
}
}
sw.WriteLine("---------------------------------------------------------------------------------------------");
}
buffer.Position = 0L;
context.Request.Body = buffer;
}
}
}
catch
{
}
finally
{
await next.Invoke();
// Restore the original stream.
context.Request.Body = stream;
}
});
//ExpireTimeSpan and SlidinExpiration only work when UseTokenLifetime = false
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// This is NOT ASP.NET Session Timeout (that should be set to same value in web.config)
// This is the expiration on the cookie that holds the Azure AD token
ExpireTimeSpan = TimeSpan.FromMinutes(Convert.ToDouble(expirationTimeSpan)),
// Set SlidingExpiration=true to instruct the middleware to re-issue a new cookie
// with a new expiration time any time it processes a request which is more than
// halfway through the expiration window.
SlidingExpiration = true,
Provider = new CookieAuthenticationProvider
{
// This method is called every time the cookie is authenticated, which
// is every time a request is made to the web app
OnValidateIdentity = CookieAuthNotification.OnValidateIdentity
}
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
UseTokenLifetime = false,
/*
* Skipping the Home Realm Discovery Page in Azure AD
* http://www.cloudidentity.com/blog/2014/11/17/skipping-the-home-realm-discovery-page-in-azure-ad/
*/
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = OpenIdConnectNotification.RedirectToIdentityProvider,
MessageReceived = OpenIdConnectNotification.MessageReceived,
SecurityTokenReceived = OpenIdConnectNotification.SecurityTokenReceived,
SecurityTokenValidated = OpenIdConnectNotification.SecurityTokenValidated,
AuthorizationCodeReceived = OpenIdConnectNotification.AuthorizationCodeReceived,
AuthenticationFailed = OpenIdConnectNotification.AuthenticationFailed
},
});
}
答
我结束了创建一个单独的中间件令牌从所述主体移动到头部
public class AlexaJWTMiddleware : OwinMiddleware
{
private readonly OwinMiddleware _next;
public AlexaJWTMiddleware(OwinMiddleware next) : base(next)
{
_next = next;
}
public override Task Invoke(IOwinContext context)
{
var stream = context.Request.Body;
if (context.Request.Headers.ContainsKey("SignatureCertChainUrl")
&& context.Request.Headers["SignatureCertChainUrl"]
.Contains("https://s3.amazonaws.com/echo.api/echo-api-cert-4.pem")
&& !context.Request.Headers.ContainsKey("Authorization"))
{
try
{
using (var buffer = new MemoryStream())
{
stream.CopyToAsync(buffer);
var bodyBuffer = new byte[buffer.Length];
buffer.Position = 0L;
buffer.Read(bodyBuffer, 0, bodyBuffer.Length);
var body = Encoding.UTF8.GetString(bodyBuffer);
dynamic json = JObject.Parse(body);
if (json?.session?.user?.accessToken != null)
{
context.Request.Headers.Add("Authorization",
new string[] { string.Format("Bearer {0}", json?.session?.user?.accessToken) });
}
buffer.Position = 0L;
context.Request.Body = buffer;
}
}
catch
{
}
finally
{
// Restore the original stream.
context.Request.Body = stream;
}
}
else
{
return _next.Invoke(context);
}
return _next.Invoke(context);
}
}
,然后加入JWT认证除了openId之外
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.Use(typeof(AlexaJWTMiddleware));
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = domain,
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:AppIdUri"]
},
AuthenticationType = "OAuth2Bearer",
});
//ExpireTimeSpan and SlidinExpiration only work when UseTokenLifetime = false
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// This is NOT ASP.NET Session Timeout (that should be set to same value in web.config)
// This is the expiration on the cookie that holds the Azure AD token
ExpireTimeSpan = TimeSpan.FromMinutes(Convert.ToDouble(expirationTimeSpan)),
// Set SlidingExpiration=true to instruct the middleware to re-issue a new cookie
// with a new expiration time any time it processes a request which is more than
// halfway through the expiration window.
SlidingExpiration = true,
Provider = new CookieAuthenticationProvider
{
// This method is called every time the cookie is authenticated, which
// is every time a request is made to the web app
OnValidateIdentity = CookieAuthNotification.OnValidateIdentity
}
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
UseTokenLifetime = false,
/*
* Skipping the Home Realm Discovery Page in Azure AD
* http://www.cloudidentity.com/blog/2014/11/17/skipping-the-home-realm-discovery-page-in-azure-ad/
*/
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = OpenIdConnectNotification.RedirectToIdentityProvider,
MessageReceived = OpenIdConnectNotification.MessageReceived,
SecurityTokenReceived = OpenIdConnectNotification.SecurityTokenReceived,
SecurityTokenValidated = OpenIdConnectNotification.SecurityTokenValidated,
AuthorizationCodeReceived = OpenIdConnectNotification.AuthorizationCodeReceived,
AuthenticationFailed = OpenIdConnectNotification.AuthenticationFailed
},
});
}
你介意共享302重定向的地址吗?你配置了[认证/授权](https://docs.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-how-to-configure-active-directory-authentication ?toc =%2fazure%2fapp-service%2ftoc.json)用于部署在Azure上的Web API? –
该文章中的哪个设置是执行302重定向的网址? Web API实际上是一个MVC应用程序,我在其中添加了一个控制器来处理alexa电话。该应用程序是在几年前配置的,并且在alexa中链接的用户可以在Web应用程序中完全登录。 –
无法确定没有附加信息的根本原因。您可以分享地址重定向,并查看是否有人可以提供有用的建议。 –