HandleUnauthorizedRequest in ASP.Net Web API - asp.net

I am developing a ASP.Net Web API application and I have used AuthorizeAttribute for the authentication. When the authentication fails, the code that executes is this.
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
HttpContext.Current.Response.AddHeader("AuthenticationStatus", "NotAuthorized");
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
return;
}
This code results to display a Unauthorized request page from the browser but what I want is to display a custom page which I have designed. How do I do that?

Check this out: http://weblogs.asp.net/jgalloway/archive/2012/03/23/asp-net-web-api-screencast-series-part-6-authorization.aspx
What it basically says, you have to check the result code on the client side, and in case it is 401 (Unauthorized), redirect the user to the custom page you've designed:
$(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/';
}
}
});
});
});

I don't think you can redirect to your custom page from within HandleUnathorizedRequest if you are using WebApi. The code result displays Unauthorized request page because that is how your browser responds to 403 code. WebApi works on HttpMessage exchange and by default uses either Json or Xml media type. If you want to return your customized page as text/html then you will have to write your own media formatter as explained here: http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters.

Related

ajax call status is 200 but it is not successfull

I working on mvc asp.net project. I call my controller function with ajax, the call status is 200 but it is not successful, and goes to error section.
service:
public async Task<IEnumerable<TeamDto>> GetAllTeamsList()
{
var teams = await _teamRepository.GetAll().Include(u => u.Users).ThenInclude(m => m.User).ToListAsync();
return ObjectMapper.Map<IEnumerable<TeamDto>>(teams);
}
Controller:
public async Task<IEnumerable<TeamDto>> GetTeams()
{
var teams = await _teamAppService.GetAllTeamsList();
return teams;
}
js file:
$.ajax(
{
type: "GET",
url: "/App/Team/GetTeams",
success: function (data) {
///
},
error: function (data) { console.log("it went bad " + JSON.stringify(data)); }
});
Error:
TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
this is what I get when copy the url in the browser:
{"result":[{"tenantId":1,"name":"admin
team","users":[{"tenantId":1,"userId":2,"teamId":58,"user":{"profilePictureId":null,"shouldChangePasswordOnNextLogin":false,"signInTokenExpireTimeUtc":null,"signInToken":null,"googleAuthenticatorKey":null,"pin":"1234","hourlyRate":0.00,"payrollId":"","warehouseId":1,"tandaUser":null,"normalizedUserName":"ADMIN","normalizedEmailAddress":"ADMIN#DEFAULTTENANT.COM","concurrencyStamp":"bd7ee91e-587b-4ae2-bc97-be2ce7d7789b","tokens":null,"deleterUser":null,"creatorUser":null,"lastModifierUser":null,"authenticationSource":null,"userName":"admin","tenantId":1,"emailAddress":"admin#defaulttenant.com","name":"admin","surname":"admin","fullName":"admin
admin","password":"AQAAAAEAACcQAAAAENfcSE+zBppFKVxKUynGBiy4WZgDU3C3gbbWnQUdEyBb5J/S0uLkcqk+2MwM0DXxjw==","emailConfirmationCode":null,"passwordResetCode":null,"lockoutEndDateUtc":null,"accessFailedCount":1,"isLockoutEnabled":true,"phoneNumber":"","isPhoneNumberConfirmed":false,"securityStamp":"07a4d582-7233-3fbc-f3f7-39f015ee388b","isTwoFactorEnabled":false,"logins":null,"roles":null,"claims":null,"permissions":null,"settings":null,"isEmailConfirmed":true,"isActive":true,"isDeleted":false,"deleterUserId":null,"deletionTime":null,"lastModificationTime":"2020-09-30T02:54:34.402372Z","lastModifierUserId":null,"creationTime":"2019-09-05T23:27:47.8514365Z","creatorUserId":null,"id":2},"team":{"tenantId":1,"name":"admin
team","users":[
Open up the developer tools and look at the URL it is trying to request. Normally in the context of the application, you don't have the /App defined. In fact, you can use ASP.NET MVC Url helper to get the action method, to make sure the path is correct:
$.ajax({
type: "GET",
url: "#Url.Action("GetTeams", "Team")",
Also, normally you would return data via JSON from the controller like:
public async Task<IEnumerable<TeamDto>> GetTeams()
{
var teams = await _teamAppService.GetAllTeamsList();
return Json(teams, JsonRequestBehavior.AllowGet);
}
And maybe that would make a difference, using Json() from the asp.net mvc controller. Note AllowGet ensures that GET requests on an action returning JSON works, otherwise it will be blocked and return an error.

nativescript authenticating at backend web api

I am new to mobile development. My project is build using asp.net. For authentication I am using build it UserManager & User.Identity.
I have bunch of existing web apis and I wish to use them from mobile app.
I know , I could pass a secret hash to web api after authenticating, but that would involve a huge code refactoring.
I been wondering if there other ways to handle authentication & authorization with nativescript & asp.net .
Do you know any useful resources for this topic?
Many thanks for your help!
It depends quite heavily on your API structure, but I would recommend somethign like this:
Firstly you would need to use the Nativescript Http module. An implementation to get a an HTTP GET calls returned header might look like this:
http.request({ url: "https://httpbin.org/get", method: "GET" }).then(function (response) {
//// Argument (response) is HttpResponse!
//for (var header in response.headers) {
// console.log(header + ":" + response.headers[header]);
//}
}, function (e) {
//// Argument (e) is Error!
});
So your backend might return a JSON Web Token as a header. In which case on the success callback you would probably want to store your token in the applications persistent memory. I would use the Application Settings module, which would look something like:
var appSettings = require("application-settings");
appSettings.setString("storedToken", tokenValue);
Then before you make an API call for a new token you can check if there is a stored value:
var tokenValue = appSettings.getString("storedToken");
if (tokenValue === undefined {
//do API call
}
Then with your token, you would want to make an API call, e.g. this POST and add the token as a header:
http.request({
url: "https://httpbin.org/post",
method: "POST",
headers: { "Content-Type": "application/json", "Auth": tokenValue },
content: JSON.stringify({ MyVariableOne: "ValueOne", MyVariableTwo: "ValueTwo" })
}).then(function (response) {
// result = response.content.toJSON();
// console.log(result);
}, function (e) {
// console.log("Error occurred " + e);
});
Your backend would need to check the Auth header and validate the JWT to decide whether to accept or reject the call.
Alternatively, there some nice plugins for various Backends-as-a-Service, e.g. Azure and Firebase

Spark-java redirect - browser does not redirect

Ok, so I try to follow Spark documentation and I want to perform simple redirect in my Single Page Application. My code looks like this:
post("/users/login", (req, res) -> {
ObjectMapper mapper = new ObjectMapper();
User creation = mapper.readValue(req.body(), User.class);
User user = userService.getUser(creation.getLogin());
if (user.getPassword().equals(creation.getPassword())) {
req.session().attribute("userid", creation.getLogin());
System.out.println("OK");
res.status(201);
res.redirect("/index.html");
return "";
}
System.out.println("BAD");
return null;
} , json());
Basically, I have three static html files: registration.html, login.html and index.html. I read stuff concerning staticFileLocation so I added at the beginning of main function following line of code:
staticFileLocation("/public");
When I type correct login and password I find in the network view in Chrome that I have GET request with status 200, OK, to http://localhost:4567/index.html. However, the browser does nothing and does not redirect me to that page. Can you tell me what I am doing wrong?
EDIT:
Here's javascript code that handles log in on the client side:
app.controller('LoginUserCtrl', function($scope, $http) {
$scope.loginUser = {};
$scope.submitForm = function() {
$http({
method : 'POST',
url : 'http://localhost:4567/users/login',
data : $scope.loginUser,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).success(function() {
console.log("User logged successfully");
console.log($scope.loginUser);
}).error(function() {
console.log("Unknown error while logging user");
});
};
});
What's wrong is that you're redirecting to an HTML page in a post endpoint that's supposed to return Json data. You have to return a single json if authentication succeeded or failed, like {"auth": "OK"} or {"auth": "NOK"}, and decide where to redirect to from Javascript based in it's information.
It's because res.redirect will send a redirect http header(HTTP status values 301, 302, 303 and 307) to the browser,
but the browser only can redirect in get, NOT work in post or put or delete (Tested in chrome. Notice that a redirect request was sent by browser, but the page just not change...).
See:
http://www.alanflavell.org.uk/www/post-redirect.html

How to send data from URL to Post Request Method?

i'm developing an MVC4 application and using Web API for my web services to send data for android application and i need some testing on the results so when i use GET Request Method i put in the browser this URL
http://localhost:2100/api/Accounts/LogIn?UserName=Fadi&PassWord=123456
this is my method
[HttpGet]
public ConfrmationMessage LogIn(string UserName, string PassWord)
{
ConfrmationMessage flag = new ConfrmationMessage();
if (WebSecurity.Login(UserName, PassWord))
{
flag.status = "LogedIn";
return flag;
}
else
{
flag.status = "The user name or password provided is incorrect.";
return flag;
}
}
and every thing work fine but when i'm using an [HttpPost] and use this URL again
http://localhost:2100/api/Accounts/LogIn?UserName=Fadi&PassWord=123456
it give me this error
{"Message":"The requested resource does not support http method 'GET'."}
so i did do some search and find that the post method use anther way to put data from URL link but still can not understand how to write the correct URL for the post method so any help and thanks in advance.
you submit a post request via a form element like so (there are more attributes you can add but you can look these up easily.
<form action="~/api/Accounts/LogIn" method="POST">
<!--input elements here -->
</form>
or through an ajax call (requires jquery)
$.ajax({
url: "~/api/Accounts/LogIn",
type: "POST",
data: { UserName: "Fadi", PassWord: "123456" }
success: function(result) {
//do something when response is successful (result is the response)
},
error: function(jqXHR, textStatus, errorThrown) {
//will return exception info from server
//jqXHR is the request in xml format
//textStatus is the description of the exception (if there is one)
//errorThrown is the excception object thrown (if there is one)
}
});

ASP .NET 4 Wev Api controller - modify response type

Let’s say I’ve got a simple Web API controller. I want to return a basic .NET type as a result. For example:
public class LoginController : ApiController
{
[HttpPost]
public bool Authenticate(LoginUserViewModel loginUserViewModel)
{
return true;
}
}
I’m getting different results in different browsers even if the request is exactly the same for all of them.
In Chrome and IE7 I get Content-Type in Response Headers as application/json; charset=utf-8, and response value equal to "true".
Firefox recognizes response Content-Type as application/xml; charset=utf-8 and sets response value to:
"<boolean xmlns="http://schemas.microsoft.com/2003/10/Serialization/">true</boolean>"
Is there any way to set response type on the server-side so it is always the same?
Thanks.
UPDATE: Here is JavaScript that I use to call my controller.
Ext.Ajax.request({
async: false,
url: 'Login/Authenticate',
defaultHeaders: { 'Accept': 'application/json' },
jsonData: user,
success: function (response, options) {
if (response.responseText !== 'true') {
Ext.Msg.alert('Error', 'Login failed, please try again');
} else {
document.location = 'Main.aspx';
}
},
failure: function (response, options) {
Ext.MessageBox.hide();
Ext.Msg.alert('Error', 'Server error. Cannot authenticate user.');
}
});
This is because browsers send different Accept headers. Web API uses the accept header to determine the content-type of the response. By default Web API loads up a few different formatters into it's configuration.Formatters collection.
One way to force the response of to be a specific media-type is to remove all the existing formatters and add only the one you want.
configuration.Formatters.Clear();
configuration.Formatters.Add(new JsonMediaTypeFormatter());

Resources