HOw to redirect sessiont timeout page when do AJAX call - ajax

In MVC application, I have made most of the CRUD operations call using AJAX.
Problem is , when session gets timeout then, its unable to redirect to session time out page.
Below is the related code which works fine when there is no AJAX call.
[AttributeUsage(AttributeTargets.Class)] //| AttributeTargets.Method
public class ControllerLogAndAccessFilter : FilterAttribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
\\check if session is null then redirect to session time out page.
}
}
For login, i just check against the databsae, there is nothing for memebrship provider.
[HttpPost]
public JsonResult Login(string username, string password, bool RememberMe)
{
try
{
UserDTO accDTO = new UserDTO ()
{
UsernAme = username,
Password = DataEncryption.EncryptPassword(password)
};
UserDTO AccDTO = _iAccount.UserAuthentication(accDTO);
if (AccDTO != null)
{
Session["UserId"] = 1;
Session["userdto_Session"] = AccDTO;
// Remember me
HttpCookie myCookie = new HttpCookie("appCookie");
//chkRememberMe.Checked;
if (RememberMe)
{
myCookie.Values.Add("username", username);
myCookie.Values.Add("password", password);
myCookie.Expires = DateTime.Now.AddMinutes(20);
}
else
{
myCookie.Values.Add("username", string.Empty);
myCookie.Values.Add("password", string.Empty);
myCookie.Expires = DateTime.Now.AddMinutes(5);
}
Response.Cookies.Add(myCookie);
// Remember me
return Json(AccDTO.SID, JsonRequestBehavior.AllowGet);
}
else
{
return Json(null);
}
}
catch (Exception ex)
{
}
return null;
}
AJAX Call is made for login and all CRUD operation are using $.AJAX({...});.

Ajax requests should be handled at client side itself, Try this
Attribute:
[AttributeUsage(AttributeTargets.Class)] //| AttributeTargets.Method
public class ControllerLogAndAccessFilter : FilterAttribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
//TO HANDLE AJAX REQUESTS
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
//If session is null
filterContext.Result = new JsonResult
{
Data = new
{
// put a message which sentto the client
message = "Session Time out"
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}else{
//
}
}
}
In your javascript
$.ajax(function(){
url:"",
success: function (result) {
if(result.message == "Session Time out"){
//Session timed out handle it
//window.location.href = session timeout url
}
},
});

Related

.Net Framework API Controller won't recognize Route attributes

I have created an API Controller using .Net Framework as follows:
public class ApplicationUsersController : ApiController
{
[Route("api/ApplicationUser/{username}/{password}")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult GetApplicationUser(string username, string password)
{
ApplicationUser user = new ApplicationUser()
//Code to populate user.
return Ok(user);
}
[Route("api/ApplicationUser/{username}")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult GetApplicationUser(string username)
{
ApplicationUser user = new ApplicationUser()
//Code to populate user.
return Ok(user);
}
// PUT: api/ApplicationUsers/5
[Route("api/ApplicationUser/{username}")]
[ResponseType(typeof(void))]
public IHttpActionResult PutApplicationUser(string username, ApplicationUser ApplicationUser)
{
//Code to update user
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/ApplicationUsers
[Route("api/ApplicationUser")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult PostApplicationUser(ApplicationUser ApplicationUser)
{
//Code to create new user
return Ok(ApplicationUser);
// return CreatedAtRoute("api/ApplicationUser/{username}", new { username = ApplicationUser.UserName }, ApplicationUser);
}
// DELETE: api/ApplicationUsers/5
[Route("api/ApplicationUser/{username}")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult DeleteApplicationUser(string username)
{
//Code to populate user then delete the record.
return Ok(user);
}
}
When I make a Get call to api/ApplicationUser/{username}/{password}, it works fine. If I make a Post call to api/ApplicationUser, it works fine. If I make a Get, Put or Delete call to api/ApplicationUser/{username}, I get a "not found" error. Is there something else I need to do to make it recognize the route?
Thanks,
Jim
**** Update ****
I have discovered that it will recognize the route as long as the username doesn't end with .something such as .com. The thing is, I am using email addresses as the username. Is there a rule somewhere that a REST url can't end with .somthing? Is there a way around this?
The problem was the format of the parameters. Apparently a url can't end with a .com or other domain suffix. What I did was to convert the parameters to Base64. I created these two extension functions.
public static string ToBase64(this string value)
{
try
{
byte[] bytes = Encoding.UTF8.GetBytes(value);
return Convert.ToBase64String(bytes);
}
catch (Exception)
{
return value;
}
}
public static string FromBase64(this string value)
{
try
{
byte[] bytes = Convert.FromBase64String(value);
return Encoding.UTF8.GetString(bytes);
}
catch(Exception)
{
return value;
}
}
In the controller, I did something like:
[Route("api/ApplicationUser/{username}")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult GetApplicationUser(string username)
{
username = username.FromBase64();
ApplicationUser user = new ApplicationUser()
//Code to populate user.
return Ok(user);
}
In the client, I did something like:
async Task<ApplicationUser> IApplicationUserService.GetApplicationUser(string username)
{
username = username.ToBase64();
ApplicationUser ret = null;
var response = await _httpClient.GetAsync($"api/ApplicationUser/{username}");
if (response.IsSuccessStatusCode)
{
ret = await JsonSerializer.DeserializeAsync<ApplicationUser>
(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
return ret; ;
}
Cheers,
Jim

How to redirect user after login Web API?

If my user encounters a controller with my attribute [CustomAuthorize], he is redirected to the login page where he gets his JWT token. But on successful login I want to redirect him to the place where he initially wanted to be(the URL he wrote before was redirected to login page). what's the best way to save the path?
That's my CustomAuthorizeAttribute:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new RedirectResult("~/Login");
return;
}
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectResult("~/Login");
return;
}
}
}
In other words, how to know from which request the user came from?
I'be decided to write pass a parameter to Login Controller like this
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
var values = new RouteValueDictionary(new
{
controller = "Login",
RequestedAddress = filterContext.RequestContext.RouteData.Values.Values.First()
});
filterContext.Result = new RedirectToRouteResult(values);
return;
}
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectResult("~/Login");
return;
}
}
And then to get it like this
public class LoginController : Controller
{
public ActionResult Index(String RequestedAddress)
{
return View();
}
}

SignalR Authorize attribute not called

I have a hub that does not convert the token located at Authorization:Bearer eyjsdalfsadlfjffdafs... in the request header to an identity. The rest of the API works fine with standard http verbs however for some reason SignalR is not authorizing the token into a user.
public class ChatHub : Hub
{
[Authorize]
public override Task OnConnected()
{
// error context.user.identity.name =""
var userId = int.Parse(Context.User.Identity.Name);
return base.OnConnected();
}
....
}
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
JwtHandler - this part of the filter is not called when the client connects to the hub even though onConnect() is attributed with [Authorize]
public class JwtHandler : DelegatingHandler
{
private const string ISSUER = "Issuer";
private const string AUDIENCE = "Audience";
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
byte[] key = Convert.FromBase64String("SecretKey");
try
{
var headers = request.Headers;
if(headers.Authorization != null)
{
if(headers.Authorization.Scheme.Equals("Bearer"))
{
string jwt = request.Headers.Authorization.Parameter;
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
TokenValidationParameters parms = new TokenValidationParameters()
{
ValidAudience = AUDIENCE,
ValidIssuers = new List<string>(){ISSUER},
IssuerSigningToken = new BinarySecretSecurityToken(key),
};
SecurityToken validated = new JwtSecurityToken(jwt);
var principal = tokenHandler.ValidateToken(jwt, parms,out validated);
Thread.CurrentPrincipal = principal;
if(HttpContext.Current !=null)
{
HttpContext.Current.User = principal;
}
}
}
var response = await base.SendAsync(request, cancellationToken);
if(response.StatusCode == HttpStatusCode.Unauthorized)
{
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Bearer", "error=\"invalid_token\""));
return response;
}
return response;
}catch (Exception)
{
var response = request.CreateResponse(HttpStatusCode.Unauthorized);
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Bearer", "error=\"invalid_token\""));
return response;
}
}
}
Try validating the jwt token in the OWIN middleware. In your Startup.cs add:
public void Configuration(IAppBuilder app)
{
app.UseJwtBearerAuthentication(
new Microsoft.Owin.Security.Jwt.JwtBearerAuthenticationOptions() {
AllowedAudiences = new string[] { ALLOWEDAUDIENCE },
IssuerSecurityTokenProviders = new[] {
new SymmetricKeyIssuerSecurityTokenProvider(ISSUER, System.Convert.FromBase64String(cKey))
}
});
app.MapSignalR();
}

Using both OAuth and Basic Auth in Asp.Net Web Api with Owin

I've implemented OAuth authentication in my Web Api project based on these blog posts
It works well, including the refresh token logic.
I want to add an option for basic authentication as well for a couple of calls for scheduled jobs.
I've tried adding a Basic Auth solution as middleware but I'm still getting 401 asking for the Bearer token.
I can get it to work by removing the [Authorize] attribute from those api calls and checking manually in code if the user is authenticated but seems like the wrong way to solve it.
Is there a way to support both Basic Auth and OAuth authentication using OWin?
How about you attribute your actions or controller with you want to implement Basic authentication with the attribute [OverrideAuthentication] Then you create custom authentication filter attribute which inherits from Attribute, IAuthenticationFilter as the code below
public class BasicAuthenticationAttribute : Attribute, IAuthenticationFilter
{
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var req = context.Request;
// Get credential from the Authorization header
//(if present) and authenticate
if (req.Headers.Authorization != null && "basic".Equals(req.Headers.Authorization.Scheme, StringComparison.OrdinalIgnoreCase))
{
var rawCreds = req.Headers.Authorization.Parameter;
var credArray = GetCredentials(rawCreds);
var clientId = credArray[0];
var secret = credArray[1];
if (ValidCredentials(clientId, secret))
{
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, clientId)
};
var identity = new ClaimsIdentity(claims, "Basic");
var principal = new ClaimsPrincipal(new[] { identity });
// The request message contains valid credential
context.Principal = principal;
}
else
{
context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
}
}
else
{
context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
}
return Task.FromResult(0);
}
private string[] GetCredentials(string rawCred)
{
var encoding = Encoding.GetEncoding("UTF-8");
var cred = encoding.GetString(Convert.FromBase64String(rawCred));
var credArray = cred.Split(':');
if (credArray.Length == 2)
{
return credArray;
}
else
{
return credArray = ":".Split(':');
}
}
private bool ValidCredentials(string clientId, string secret)
{
//compare the values from web.config
if (clientId == secret)
{
return true;
}
return false;
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context,CancellationToken cancellationToken)
{
context.Result = new ResultWithChallenge(context.Result);
return Task.FromResult(0);
}
public class ResultWithChallenge : IHttpActionResult
{
private readonly IHttpActionResult next;
public ResultWithChallenge(IHttpActionResult next)
{
this.next = next;
}
public async Task<HttpResponseMessage> ExecuteAsync( CancellationToken cancellationToken)
{
var response = await next.ExecuteAsync(cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Basic"));
}
return response;
}
}
public bool AllowMultiple
{
get { return false; }
}
}
Now you use it to attribute you controllers or actions as the code below:
[OverrideAuthentication]
[BasicAuthentication]
[Route("")]
public async Task<IHttpActionResult> Get()
{
}
Notice how we are creating claims identity and setting the Authentication scheme to Basic, you can put any claims you want here.

How to write into session with web api?

I am writing an authentication code. I am authenticating against the web server. currently my code take the username and password from xcode and send it over to the web service via the URL which then returns a json string that I am reading in xcode. When the connection is succefull I want to create a session and in xcode i want to read that session.
Web Api:
public class SessionController : ApiController
{
public bool loggedin = false;
public class MyHttpControllerHandler: HttpControllerHandler, IRequiresSessionState
{
public MyHttpControllerHandler(RouteData routeData): base(routeData)
{ }
}
public class MyHttpControllerRouteHandler : HttpControllerRouteHandler
{
protected override IHttpHandler GetHttpHandler(
RequestContext requestContext)
{
return new MyHttpControllerHandler(requestContext.RouteData);
}
}
public void Authenticate(string txtLoginId, string txtPassword)
{
Subs objSub = SubService.GetSubs(txtLoginId.Trim(), txtPassword.Trim());
if (objSub != null)
{
loggedin = true;
}
else
loggedin = false;
}
public string Get(string user, string pass)
{
byte[] data = Convert.FromBase64String(pass);
string password = Encoding.UTF8.GetString(data);
Authenticate(user, password);
if(loggedin == true)
{
var session = HttpContext.Current.Session;
session["Time"] = DateTime.Now;
return "Session Time: " + session["Time"] + user;
}else
return "Session is not availabe " + user;
}
}
it returns the following error on this line,
session["Time"] = DateTime.Now;
ExceptionMessage":"Object reference not set to an instance of an object."

Resources