1

I use an external provider in order to authenticate user in my ASP.NET MVC app without any problem. However, I also need to authorize users in order to prevent them from direct access or expired access (session for 2 min). I had used ASP.NET Identity before, but this time I do not need to keep neither users nor roles on the table and for this reason I need a quick and good workaround for this problem. So, how can I prevent a user accessing the In dex page of my app without authenticating by the provider that I use. Similarly I also need to check if there is more than 2 minutes after user's last action and in such sitıuation I need to redirect user to Login page. I tried to use OWIN Cookie, but unfortunately I cannot logout user by using at least 10 different approach :(

Startup:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
    }

    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),

            //other options
            ExpireTimeSpan = TimeSpan.FromMinutes(1)
            //Provider = new CookieAuthenticationProvider(),
            //CookieName = "MyCookieName",
            //CookieHttpOnly = true
        });
    }
}

Controller:

[HttpGet]
public ActionResult Login(string code)
{
    //At this stage I want to force user to sign out, but none of the following methods work

    //method 1
    HttpContext.GetOwinContext().Authentication.SignOut("ApplicationCookie");

    //method 2
    var ctx = Request.GetOwinContext();
    var authManager = ctx.Authentication;
    authManager.SignOut("ApplicationCookie");
    //or        
    //authManager.SignOut();

    //method 3
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

    //method 4 (using only one of them at a time)
    Request.GetOwinContext().Authentication.SignOut();
    Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
    HttpContext.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);


    //check session
    var isAuthenticated = HttpContext.GetOwinContext().Authentication.User.Identity.IsAuthenticated; // >>> always returns true
    string tc = HttpContext.GetOwinContext().Authentication.User.Identity.Name; // >>> always returns name value


    //if user is authenticated via OAuth2.0
    if (user.isAuthenticated)
    {
        var claims = new[] {
        new Claim(ClaimTypes.Name, user.Name)
    };

        var identity = new ClaimsIdentity(claims, "ApplicationCookie");

        //// Add roles into claims
        //var roles = _roleService.GetByUserId(user.Id);
        //if (roles.Any())
        //{
        //    var roleClaims = roles.Select(r => new Claim(ClaimTypes.Role, r.Name));
        //    identity.AddClaims(roleClaims);
        //}

        var context = Request.GetOwinContext();
        var authManager = context.Authentication;

        authManager.SignIn(new AuthenticationProperties
        { IsPersistent = false }, identity); // ??? I am not sure if IsPersistent should be true ? 

        return View();
    }

    // login failed
    return RedirectToAction("Account", "Login");
}

4 Answers4

1

Finally I have fixed the problem by using OWIN cookie authentication. Here is the code for those who might need to use OWIN cookie authentication on ASP.NET MVC.

On the other hand, I would really like to integrate JWT to my ASP.NET MVC project, but unfortunately was not able to do. However, many thanks and voted up the answers that are also helpful for me.

Startup:

public void Configuration(IAppBuilder app)
{
    ConfigureAuth(app);
}

public void ConfigureAuth(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        LogoutPath = new PathString("/Account/LogOff"),
        ExpireTimeSpan = TimeSpan.FromMinutes(5),
        SlidingExpiration = true,
        Provider = new CookieAuthenticationProvider(),
        CookieName = "YOUR_COOKIE_NAME",
        CookieHttpOnly = true,
        // !!! Using this setting "Always" causing "302 Redirect..." error while ddebugging >>>
        CookieSecure = CookieSecureOption.SameAsRequest 
    });
}

AccountController:

public ActionResult Login()
{
    //authenticate user
    var user = db.GetUser("John");

    if (user != null)
    {
        var claims = new[] {
            new Claim(ClaimTypes.Name, user.Name),
            new Claim(ClaimTypes.Email, user.Email)
            //you can add more claims
        };

        var identity = new ClaimsIdentity(claims, "ApplicationCookie");

        // Add roles into claims
        var roles = _roleService.GetByUserId(user.Id);
        if (roles.Any())
        {
            var roleClaims = roles.Select(r => new Claim(ClaimTypes.Role, r.Name));
            identity.AddClaims(roleClaims);
        }

        var context = Request.GetOwinContext();
        var authManager = context.Authentication;

        authManager.SignIn(new AuthenticationProperties
            { IsPersistent = true }, identity);

        return RedirectToAction("Index", "Home");
    }
    // login failed. 
    return RedirectToAction("Login", "Account");
}
0

You need to set the [Authorize] attribute on the action and/or controller.

And about the session only last for 2 minutes. You can put the timestamp in a session cookie when the user logins and then build a middleware to check the session value each time an action is made. If the session value is older than 2 minutes log out the user.

How to use session:

In Startup file add:

services.AddSession(options =>
{
   options.Cookie.SecurePolicy = CookieSecurePolicy.Always; 
});

and

app.UseSession();
//middleware for checking the 2 minute limit
app.UseMiddleware<SignoutMiddleware>();

Add the session wherever your user gets logged in:

HttpContext.Session.SetString(subjectId, DateTime.Now);

Middleware:

public class SignoutMiddleware
{
    private readonly RequestDelegate _next;

    public SignoutMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {

        var sessionExpire = context.Session.GetString(context.User.GetSubjectId());
        //Do some logic here
        await _next.Invoke(context);
    }
}

As for what your code currently does for login you probably needs to change some. But there should be many tutorials if you just google some :)

President Camacho
  • 1,860
  • 6
  • 27
  • 44
  • `[Authorize]` part is ok, thanks a lot. Actually I had used it but did not think it works with Owin Cookie :) Regarding to session part, could you pls post an example? On the other hand, is the code above is ok or is there any update needed on it? –  Apr 01 '20 at 10:37
  • Updated with session – President Camacho Apr 01 '20 at 10:54
  • Thanks a lot for reply. I just started to apply it but encounter error on services.AddSession(options => ... part. I am not sure if it is suitable for ASP.NET MVC or how can I apply it to MVC. Any idea? –  Apr 01 '20 at 21:13
  • Do you use .net core or .net framework? In your Startup where you use services.AddMvc(); you can do AddSession(options => ... – President Camacho Apr 01 '20 at 21:51
  • I use ASP.NET MVC as I stated in the beginning of question. Thanks in advance... –  Apr 02 '20 at 07:00
  • Thanks a lot for your helps, but following the examples I cannot proceed as some of the incompatibilities between .NET Core and .NET MVC I use. Or some of the missing parts in the examples. I really spent too much time and need I quick solution. However, there are almost no applicable example for using JWT in ASP.NET MVC. So, I try to use OWIN Cookie as explained on https://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/. I would prefer to use JWT but have not managed to integrate :( –  Apr 02 '20 at 09:45
  • As I stated my answer above, I ended up using OWIN Cookie Authentication. Many thanks for your help. Voted up ;) –  Apr 02 '20 at 23:19
0

You could use a Entity Framwork, JSON Web Token (JWT) and Claims. It is really easy to limit the amount of time (days, hours, minutes) you want a user to have access to a section of your Controllers with JWTs.

You can limit the amount of time a JWT has access for by using the Expires object in SecurityTokenDescriptor. So in your case I would do the following:

var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name, user.Id.ToString())
                }),
                Expires = DateTime.UtcNow.AddMinutes(2),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };

There is several great FULL examples done by Jason Watmore for .NET Core with Role Based Auth and Secure Auth For Hashed Password in Database. Not sure what library you're using though so if this does not help you it would help me to help you if you specify.

Aaron Miller
  • 185
  • 11
  • Can I apply this ASP.NET MVC? On the other hand, I use EF but I do not want creating new entities as I do not keep user account or roles. Any idea? –  Apr 01 '20 at 12:46
  • Thanks a lot for your helps, but following the examples I cannot proceed as some of the incompatibilities between .NET Core and .NET MVC I use. Or some of the missing parts in the examples. I really spent too much time and need I quick solution. However, there are almost no applicable example for using JWT in ASP.NET MVC. So, I try to use OWIN Cookie as explained on https://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/. I would prefer to use JWT but have not managed to integrate :( –  Apr 02 '20 at 09:45
  • Have you read this? https://stackoverflow.com/questions/29791499/how-to-use-jwt-in-mvc-application-for-authentication-and-authorization – Aaron Miller Apr 02 '20 at 13:11
  • Yes, I have read and tried many things and articles. What about using OWIN Cookie? –  Apr 02 '20 at 13:37
  • Any help please? –  Apr 02 '20 at 16:53
  • As I stated my answer above, I ended up using OWIN Cookie Authentication. Many thanks for your help. Voted up ;) –  Apr 02 '20 at 23:20
  • Really happy to hear you got it! – Aaron Miller Apr 02 '20 at 23:27
0

I'm AmirReza that you talking before.

Edit

In order for MVC to understand anything about your JWT you basically have to tell it :-) . First, install the Jwt package from nuget:

Install-Package Microsoft.Owin.Security.Jwt Then open up your Startup.cs file and add a new funtion that will tell MVC how to consume JWT. At basics your Startup will look something like:

using System.Configuration;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler.Encoder;
using Microsoft.Owin.Security.Jwt;
using Owin;

[assembly: OwinStartupAttribute(typeof(TOMS.Frontend.Startup))]
namespace TOMS.Frontend {
 public partial class Startup 
  { 
    public void Configuration(IAppBuilder app) 
     { 
      ConfigureAuth(app);
      ConfigureOAuthTokenConsumption(app);
     }

   private void ConfigureOAuthTokenConsumption(IAppBuilder app) 
    { 
     var issuer = ConfigurationManager.AppSettings["Issuer"];
     var audienceId = ConfigurationManager.AppSettings["AudienceId"];
     var audienceSecret =  TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);

You will notice that I am placing the issuer, audienceId and audienceSecret in my Web.config file. (Those values should match the ones on your Resource Server). Also, you might want to ensure you have an updated System.IdentityModel.Tokens.Jwt running:

Update-package System.IdentityModel.Tokens.Jwt With those set, you may decorate your controller Action with the [Authorize] attribute and play ball.

UPDATE By The way, if you wish to add the values in your web.config file in order to retrieve them as I did above; simply add them under the AppSettings:

<configuration> <appSettings> <add key="Issuer" value="YOUR_ISSUER" /> <add key="AudienceId" value="YOUR_AUDIENCEID" /> <add key="AudienceSecret" value="YOUR_AUDIENCESECRET" /> </appSettings> </configuration>
Community
  • 1
  • 1
AmirReza-Farahlagha
  • 1,204
  • 14
  • 26
  • Many thanks for your reply. I just have opportunity to give a try but at the first step I encounter an error that seems to be related .Net Core. As I mentioned in one of my comments, I use ASP.NET MVC and need a workaround for ASP.NET MVC. Is there any update in your code for making it works on MVC as well? Or if it is possible to use JWT on MVC I will look on the web and try to integrate to my project. Any suggestion? Thanks again. –  Apr 01 '20 at 21:17
  • @hexadecimal I updated My answer, please check again. – AmirReza-Farahlagha Apr 01 '20 at 22:45
  • Many thanks for your helps. Now there is no problem, but I am wondering where is `ConfigureAuth()` method implementation? Should I use it as I used in my question (I think I should remove the settings in it) or should I move `ConfigureOAuthTokenConsumption()` method's content to it. What about the Controller side? You post some examples but after update I am not sure about that. On the other hand, I also look at on the web and there is another post on stackoverflow, but there is also no `ConfigureAuth()` method implementation :( –  Apr 02 '20 at 07:45
  • Thanks a lot for your helps, but following the examples I cannot proceed as some of the incompatibilities between .NET Core and .NET MVC I use. Or some of the missing parts in the examples. I really spent too much time and need I quick solution. However, there are almost no applicable example for using JWT in ASP.NET MVC. So, I try to use OWIN Cookie as explained on https://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/. I would prefer to use JWT but have not managed to integrate :( –  Apr 02 '20 at 09:44
  • As I stated my answer above, I ended up using OWIN Cookie Authentication. Many thanks for your help. Voted up ;) –  Apr 02 '20 at 23:20