In my ASP.Net Web API Project, i added [Authorize] attribute to the controller. So when i call the method it is returning error as
"Message": "Authorization has been denied for this request."
How to send Authorize Headers along with my request.
Controller
[Authorize]
[HttpPost]
public HttpResponseMessage Settings(SettingModel data)
{
--Do i need to check authorize headers manually here?
--code goes here
}
Here it is called
http://localhost/sample/api/Settings
Headers
{
Content-Type: application/json
Authorization: What value need to be send here?
}
check the answers of Darin : How to do role based authorization for asp.net mvc 4 web api
I guess you need to register the handler..
Related
Following instructions on making MS Office connect to my Asp.NET Core Web API, I am attempting to present a login redirect to MS Office for failed authentications. Following questions and answers I am attempting to include the login redirect information in the WWW-Authenticate header property. My Web API is protected with Azure AD and the Microsoft.Identity.Web library. When the authentication fails and the middleware returns the 401 Unauthorized response, the header does include the WWW-Authenticate property but it's value is only Bearer.
Q: How can update the header information to include the necessary additional redirect information?
I have tried to implement an attribute on the API, derived from IAsyncAuthorizationFilter and access the response header in that. However the middleware already returns a 401 before this attribute is called.
I have made progress by customizing the JwtBearerOptions configuration. However this approach creates an additional header item, instead of overwriting the standard value. As a result I have now 2 KeyValuePairs for the same key in the response header, which will likely have unexpected outcomes.
In my Startup.cs:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration)
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
var existingOnChallengeHandler = options.Events.OnChallenge;
options.Events.OnChallenge = async context =>
{
await existingOnChallengeHandler(context);
string headerInfo = context.Options.Challenge;
headerInfo += " resource=\"https://management.azure.com/\"";
context.Response.Headers.Append(HeaderNames.WWWAuthenticate, headerInfo);
};
});
The original answer put me on the right track. It turned out to be actually quite simple to do this once I knew to configure the JwtBearerOptions.Challenge property:
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.Challenge = $"Bearer authorization_uri=\"{authorizationUri}\"";
}
I've been trying to resolve a 401 error for the past couple days without any success.
ASP.NET Core 2.1 API hosted behind IIS. I'm trying to access the API with windows authorisation but I'm being challenged with a login prompt. If I don't enter a username and password I get a 401 error (screenshot attached). I've followed all the articles I could find and believe I have CORS configured correctly.
Based on the screenshot does this look like a CORS issue? I'm testing via swagger and am calling from what I believe is the same domain. Does anyone have any suggestions regarding what the issue may be?
From what I see in this screenshot, everything works fine. 401 is a desirable error in this scenario, it is also proof that you don't have any problems with CORS because the API responds to your requests in an adequate way.
To break through to Api you should focus on the "Response Headers" section in which the type of authentication is defined as BEARER.
From this we can conclude that authentication is token based and in practice works as follows:
By correctly logging in through Windows Authentication, WebAPI provides a response token in header that identifies you as a user.
In order to have access to API, you should store this token locally, and then make use of it by adding it to header section of each request.
To learn more about token based authentication in swagger, check
https://swagger.io/docs/specification/authentication/bearer-authentication/
To understand how tokens works, check https://jwt.io/
Below is an example of how to achieve the intended goal by configuring swagger in the startup class of asp net core application.
public void ConfigureServices(IServiceCollection services)
{
//other code removed for brevity
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My App API", Version = "v1" });
c.CustomSchemaIds((type) => type.FullName);
c.DescribeAllEnumsAsStrings();
c.DescribeAllParametersInCamelCase();
c.EnableAnnotations();
c.OperationFilter<FormFileOperationFilter>();
var apiXmlDocFileName = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var apiXmlDocFilePath = Path.Combine(AppContext.BaseDirectory, apiXmlDocFileName);
c.IncludeXmlComments(apiXmlDocFilePath);
c.AddFluentValidationRules();
c.AddSecurityDefinition("Bearer", new ApiKeyScheme() //this is desireable line
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = "header"
});
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>> { { "Bearer", Enumerable.Empty<string>() } });
});
}
After implementing this you will be able to add the token to all requests directly from the swagger UI.
You can also achieve the intended goal using Postman
https://learning.getpostman.com/docs/postman/sending-api-requests/authorization/
Hope it Helps.
i have implemented the profileService for identity server 4 to add custom claims that i want. The idea is, before the claims are added to the token, i'm calling another .net api inside the public async Task GetProfileDataAsync(ProfileDataRequestContext context) method. I'm making a httpclient.getAsync("url/getInfo") to get some info that i want to add later in the claims. GetInfo api endpoint have [Authorize] so i need the Bearer {TOKEN} in the header when i'm making the call. How can i get the Token inside ProfileService or how can i secure my request to the /getInfo endpoint?
Thanks.
I secure the route with CORS. I'm allowing to have calls only from the identity server:
In API's startup file:
services.AddCors(o => o.AddPolicy("AllowIdentityServer", builder =>
{
builder.WithOrigins(Configuration["IdentityServer"])
.AllowAnyMethod()
.AllowAnyHeader();
}));
And at the API's endpoint :
[EnableCors("AllowIdentityServer")]
I am building a ASP.Net MVC application that can work both in Web and JQuery mobile. So i am creating a seperate view for Web and JQuery mobile application. I have placed all my primary business logic services as a Web Api calls which are called by both the clients using the AngularJs which is working fine so far.
Now I was looking to introduce the security in to the application, and realized that Basic authentication is the quickest way to get going and when I looked around I found very nice posts that helped me build the same with minimal effort. Here are 3 links that I primarily used:
For the Client Side
HTTP Auth Interceptor Module : a nice way to look for 401 error and bring up the login page and after that proceed from where you left out.
Implementing basic HTTP authentication for HTTP requests in AngularJS : This is required to ensure that I am able reuse the user credentials with the subsequent requests. which is catched in the $http.
On the Server Side :
Basic Authentication with Asp.Net WebAPI
So far so good, all my WebApi calls are working as expected,
but the issue starts when I have to make calls to the MVC controllers,
if I try to [Authorize] the methods/controllers, it throws up the forms Authentication view again on MVC even though the API has already set the Authentication Header.
So I have 2 Questions:
Can We get the WebApi and MVC to share the same data in the header? in there a way in the AngularJS i can make MVC controller calls that can pass the same header information with authorization block that is set in the $http and decode it in the server side to generate my own Authentication and set the Custom.
In case the above is not possible, I was trying to make a call to a WebApi controller to redirect to a proper view which then loads the data using the bunch of WebApi calls so that user is not asked to enter the details again.
I have decorated it with the following attribute "[ActionName("MyWorkspace")] [HttpGet]"
public HttpResponseMessage GotoMyWorkspace(string data)
{
var redirectUrl = "/";
if (System.Threading.Thread.CurrentPrincipal.IsInRole("shipper"))
{
redirectUrl = "/shipper";
}
else if (System.Threading.Thread.CurrentPrincipal.IsInRole("transporter"))
{
redirectUrl = "/transporter";
}
var response = Request.CreateResponse(HttpStatusCode.MovedPermanently);
string fullyQualifiedUrl = redirectUrl;
response.Headers.Location = new Uri(fullyQualifiedUrl, UriKind.Relative);
return response;
}
and on my meny click i invoke a angular JS function
$scope.enterWorkspace = function(){
$http.get('/api/execute/Registration/MyWorkspace?data=""')
.then(
// success callback
function(response) {
console.log('redirect Route Received:', response);
},
// error callback
function(response) {
console.log('Error retrieving the Redirect path:',response);
}
);
}
i see in the chrome developer tool that it gets redirected and gets a 200 OK status but the view is not refreshed.
is there any way we can at least get this redirect to work in case its not possible to share the WebApi and MVC authentications.
EDIT
Followed Kaido's advice and found another blog that explained how to create a custom CustomBasicAuthorizeAttribute.
Now I am able to call the method on the Home controller below: decorated with '[HttpPost][CustomBasicAuthorize]'
public ActionResult MyWorkspace()
{
var redirectUrl = "/";
if (System.Threading.Thread.CurrentPrincipal.IsInRole("shipper"))
{
redirectUrl = "/shipper/";
}
else if(System.Threading.Thread.CurrentPrincipal.IsInRole("transporter"))
{
redirectUrl = "/transporter/";
}
return RedirectToLocal(redirectUrl);
}
Again, it works to an extent, i.e. to say, when the first call is made, it gets in to my method above that redirects, but when the redirected call comes back its missing the header again!
is there anything I can do to ensure the redirected call also gets the correct header set?
BTW now my menu click looks like below:
$scope.enterMyWorkspace = function(){
$http.post('/Home/MyWorkspace')
.then(
// success callback
function(response) {
console.log('redirect Route Received:', response);
},
// error callback
function(response) {
console.log('Error retrieving the Redirect path:',response);
}
);
}
this finally settles down to the following URL: http://127.0.0.1:81/Account/Login?ReturnUrl=%2fshipper%2f
Regards
Kiran
The [Authorize] attribute uses forms authentication, however it is easy to create your own
BasicAuthenticationAttribute as in your third link.
Then put [BasicAuthentication] on the MVC controllers instead of [Authorize].
I'm running a web-api webservice inside a MVC4 Forms authentication enabled website. The Forms authentication app uses the web-api webservices.
I've protected the web-api with the [Authorize] attribute.
Now when I call the web-api from the MVC4 app while the authorization ticket has expired I get an ugly browser kind of logon dialog (which doesn't work with forms authentication).
I'm not getting this on my dev machine (IIS7.5), which I don't really understand!
How can I prevent this dialog to come up? I only need to receive the 401.
John Galloway explain this nicely in his screencast at ASP.NET Web API - Authorization (A highly recommended watch)
For some api controller like one below, where you have used an Authorize attribute on it.
[Authorize]
public class CommentsController : ApiController
{
...
}
He says, If a client makes an unauthorized request, the AuthorizationFilter does the only thing that makes sense for an HTTP API - it returns an HTTP Status Code 401, Authorization Required. Again, we're back to the value of using HTTP for an API - we don't need to arrange anything, any client on any platform will know what an HTTP 401 response means.
It's up to the client to decide what to do when they get a 401. In this JavaScript / browser based sample, we'll just redirect to the login page on the client.
$(function () {
$("#getCommentsFormsAuth").click(function () {
viewModel.comments([]);
$.ajax({ url: "/api/comments",
accepts: "application/json",
cache: false,
statusCode: {
200: function(data) {
viewModel.comments(data);
},
401: function(jqXHR, textStatus, errorThrown) {
self.location = '/Account/Login/';
}
}
});
});
});
Here in the example if 401 is encountered its up to you to decide what has to be done.
Hope this helps.
Moved the site to an IIS8 server and now the problem has gone...