C# WebAPI[授权]登录时返回错误
我正在尝试使用C# WebAPI[授权]登录时返回错误,c#,asp.net-mvc,asp.net-web-api,C#,Asp.net Mvc,Asp.net Web Api,我正在尝试使用MVC5/WebAPI 2设置WebAPI,它目前正在使用默认配置和其他默认设置。当我使用浏览器中的帐户登录时,我可以使用[Authorize]属性进入常规的MVC控制器操作,例如主页在授权时显示为它应该显示的状态,但是如果我进入/api/Me(默认内置的api控制器操作)或者我使用默认MVC Web api 2脚手架构建的任何需要授权的自定义api控制器操作,我会得到如下错误: {"message":"Authorization has been denied for this
MVC5
/WebAPI 2
设置WebAPI
,它目前正在使用默认配置和其他默认设置。当我使用浏览器中的帐户登录时,我可以使用[Authorize]
属性进入常规的MVC
控制器操作,例如主页在授权时显示为它应该显示的状态,但是如果我进入/api/Me
(默认内置的api控制器操作)或者我使用默认MVC Web api 2脚手架构建的任何需要授权的自定义api控制器操作,我会得到如下错误:
{"message":"Authorization has been denied for this request."}
这是当我在Microsoft Edge中尝试它时,我还没有在我正在构建的实际客户端代码上尝试它,这是一个UWP
应用程序。我想我应该先在浏览器中进行测试,以确保一切正常
我开始看这篇文章:它似乎更倾向于Ajax
请求和spa
。我的目标是通过网络和UWP
实现工作。我可能会把更多的时间放在UWP
方面,而不是用ajax开发一个健壮的web应用程序,因为该应用程序将在intranet中运行并访问运行web api的intranet IIS服务器,所以我想在UWP中构建一个桌面客户端,并最终通过web api访问数据的Xamarin
我是否可以安全地假设,如果您使用的是像Edge这样的常规web浏览器,则当通过
[Authorize]
属性保护web Api控制器操作时,您无法访问这些操作,因为它不会在标题中发送访问令牌?因此,您可以从UWP应用程序中创建以下两种方法,或者可以将它们封装在一个类中,您可以通过DI(您的选择)注入该类
或者,如果您使用的是持票人代币,那么您可以:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer ", "string token goes here...");
我在这里发布了更多的补充信息,供那些可能正在解决这个问题的人参考,您希望从UWP或Xamarin这样的客户端访问MVC5/WebAPI 2,但需要使用Authorize属性锁定Web Api的区域 高级过程是,您不需要通过任何MVC控制器直接向/Token端点(或指定的任何端点)发送POST 首先,如果您想使用SSL进行开发,但尚未获得证书,请继续运行以下操作:
C:\Program Files (x86)\IIS Express>iisexpressadmincmd setupSslUrl -url:https://localhost:55970/ -UseSelfSigned
其中55970是本地网站的端口,我将在我的文本中提及
接下来要做的是确保覆盖客户端验证和资源授予方法上的ApplicationAuthProvider.cs,否则将遇到无效客户端或无效授予错误
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
UserManager<ApplicationUser> _userManager;
ApplicationDbContext db = new ApplicationDbContext();
_userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
try
{
ApplicationUser user = await _userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
catch (Exception ex)
{
string str = ex.ToString();
}
db.Dispose();
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId = "";
string clientSecret = "";
context.TryGetFormCredentials(out clientId, out clientSecret);
List<string> validClients = new List<string>(){ "web","Alliance_UWP","Alliance_Xamarin","Alliance_Web" };
if (validClients.Contains(clientId))
context.Validated();
}
public override异步任务GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext)
{
context.OwinContext.Response.Headers.Add(“访问控制允许来源”,新[]{“*”});
用户管理器(UserManager);;
ApplicationDbContext db=新的ApplicationDbContext();
_userManager=newusermanager(newuserstore(db));
尝试
{
ApplicationUser user=wait_userManager.FindAsync(context.UserName,context.Password);
if(user==null)
{
SetError(“无效的授权”,“用户名或密码不正确”);
返回;
}
var identity=newclaimsidentity(context.Options.AuthenticationType);
identity.AddClaim(新声明(“sub”,context.UserName));
identity.AddClaim(新声明(“角色”、“用户”));
上下文验证(身份);
}
捕获(例外情况除外)
{
string str=ex.ToString();
}
db.Dispose();
}
公共重写异步任务ValidateClientAuthentication(OAuthValidateClientAuthenticationContext)
{
字符串clientId=“”;
字符串clientSecret=“”;
TryGetFormCredentials(out clientId,out clientSecret);
List ValidClient=新列表(){“web”、“Alliance_UWP”、“Alliance_Xamarin”、“Alliance_web”};
if(validClients.Contains(clientId))
context.Validated();
}
您不需要像我在允许的客户端上那样冗长,只要“web”就可以了,您将在Http POST方法中以url编码的表单值、grant_type=“password”和用户名/密码的形式包含它。这是我编写的一个快速而肮脏的UWP客户端,它只接收用户名/密码,并通过绑定了Authorize属性的api访问我拥有的数据集。如果您不进行身份验证,您将得到一个授权错误,这正是我们想要的
这里需要注意的是,在我的客户端中,我过滤掉了自签名证书错误,因为我已经通过上述命令在IIS Express中设置了自签名证书
Uri tokenUri = new Uri(@"https://localhost:55970/Token");
// This is a test data set from my Web Api pulling data from
// Entity Framework and SQL Server protected by the Authorize attribute
Uri testCasesUri = new Uri(@"https://localhost:55970/api/Cases");
string accessToken = "";
public MainPage()
{
this.InitializeComponent();
}
private async void btn_SubmitLogin_Click(object sender, RoutedEventArgs e)
{
string username = txt_User.Text;
string password = txt_Password.Password;
HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure);
HttpClient client = new HttpClient(filter);
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("client_id", "web");
parameters.Add("grant_type", "password");
parameters.Add("username", username);
parameters.Add("password", password);
try
{
HttpResponseMessage result = await client.PostAsync(tokenUri, new HttpFormUrlEncodedContent(parameters));
string jsonResult = await result.Content.ReadAsStringAsync();
// TokenResult is a custom model class for deserialization of the Token Endpoint
// Be sure to include Newtonsoft.Json from NuGet
var resultObject = JsonConvert.DeserializeObject<TokenResult>(jsonResult);
accessToken = resultObject.AccessToken;
// When setting the request for data from Web Api set the Authorization
// header to Bearer and the token you retrieved
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
result = await client.GetAsync(testCasesUri);
jsonResult = await result.Content.ReadAsStringAsync();
} catch(Exception ex)
{
string debugBreak = ex.ToString();
}
uritokenuri=newuri(@)https://localhost:55970/Token");
//这是我的Web Api中的一个测试数据集,从中提取数据
//受Authorize属性保护的实体框架和SQL Server
Uri testCasesUri=新Uri(@“https://localhost:55970/api/Cases");
字符串accessToken=“”;
公共主页()
{
this.InitializeComponent();
}
私有异步无效btn\u SubmitLogin\u单击(对象发送方,路由目标)
{
字符串username=txt_User.Text;
字符串密码=txt_password.password;
HttpBaseProtocolFilter=新的HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure);
HttpClient=新的HttpClient(过滤器);
字典参数=新字典();
添加(“客户端id”、“web”);
添加(“授权类型”、“密码”);
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
UserManager<ApplicationUser> _userManager;
ApplicationDbContext db = new ApplicationDbContext();
_userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
try
{
ApplicationUser user = await _userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
catch (Exception ex)
{
string str = ex.ToString();
}
db.Dispose();
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId = "";
string clientSecret = "";
context.TryGetFormCredentials(out clientId, out clientSecret);
List<string> validClients = new List<string>(){ "web","Alliance_UWP","Alliance_Xamarin","Alliance_Web" };
if (validClients.Contains(clientId))
context.Validated();
}
Uri tokenUri = new Uri(@"https://localhost:55970/Token");
// This is a test data set from my Web Api pulling data from
// Entity Framework and SQL Server protected by the Authorize attribute
Uri testCasesUri = new Uri(@"https://localhost:55970/api/Cases");
string accessToken = "";
public MainPage()
{
this.InitializeComponent();
}
private async void btn_SubmitLogin_Click(object sender, RoutedEventArgs e)
{
string username = txt_User.Text;
string password = txt_Password.Password;
HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure);
HttpClient client = new HttpClient(filter);
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("client_id", "web");
parameters.Add("grant_type", "password");
parameters.Add("username", username);
parameters.Add("password", password);
try
{
HttpResponseMessage result = await client.PostAsync(tokenUri, new HttpFormUrlEncodedContent(parameters));
string jsonResult = await result.Content.ReadAsStringAsync();
// TokenResult is a custom model class for deserialization of the Token Endpoint
// Be sure to include Newtonsoft.Json from NuGet
var resultObject = JsonConvert.DeserializeObject<TokenResult>(jsonResult);
accessToken = resultObject.AccessToken;
// When setting the request for data from Web Api set the Authorization
// header to Bearer and the token you retrieved
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
result = await client.GetAsync(testCasesUri);
jsonResult = await result.Content.ReadAsStringAsync();
} catch(Exception ex)
{
string debugBreak = ex.ToString();
}