4 Replies - 404 Views - Last Post: 15 February 2019 - 07:51 AM

#1 andrewsw   User is offline

  • Stealth IT
  • member icon

Reputation: 6746
  • View blog
  • Posts: 27,775
  • Joined: 12-December 12

Angular, Identity, with separate API

Posted 10 December 2018 - 02:49 AM

I will be building an ASP.NET Core Angular application. I realise that I should have a separate (ASP.NET) API application to provide the data.

We want to use the default Identity authentication.

Do you have experience with Identity? Do you think there will be issues that I should be aware of when separating the API? How will Identity work between two applications, roughly?
Is This A Good Question/Topic? 0
  • +

Replies To: Angular, Identity, with separate API

#2 fearfulsc2   User is offline

  • D.I.C Head

Reputation: 15
  • View blog
  • Posts: 243
  • Joined: 25-May 16

Re: Angular, Identity, with separate API

Posted 15 February 2019 - 07:08 AM

I have a bit of experience working with Angular and WebAPI protection. However, I used JWT for authentication.

You would secure your API like normal such as
[Authorize]
[ApiController]
    [Route("[controller]")]
    public class UsersController : ControllerBase
    {
      // Constructor
      public UsersController() // use dependency injection in the parameters
      {
        // the rest of the thing go here
      }

     [AllowAnonymous]
     [HttpPost("authenticate")]
        public IActionResult Authenticate([FromBody]User user)
        {
            var someUser = _userService.Authenticate(user.Username, user.Password);

            if (user == null)
                return BadRequest(new { message = "Username or password is incorrect" });

            return Ok(someUser);
        }
      
    }




That's just a basic example for WebAPI and then you can create a user model class and set up a secret key for the JWT for security reasons and so forth.

When it comes to Angular, you are going to want to create a class that guards your routes
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

@Injectable({ providedIn: 'root' })
export class RouteGuard implements CanActivate {

    constructor(private router: Router) { }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        if (localStorage.getItem('currentUser')) {
            // logged in so return true
            return true;
        }

        // not logged in so redirect to login page with the return url
        this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
        return false;
    }
}



Once the user is logged in, you can also use HttpInterceptors that was introduced in Angular 4.1 or so I believe and what that will do is look at the response from the API before it gets back to the user in case you want to do something else just in case the person has access to the application but doesn't have permissions to do some things.

You can then go to using the JWTInterceptor which expands from the HttpInterceptors module. And what this does it that it adds the JWT auth token to the Authorization header for when the user is logged in so that we don't need to consistently ask for the user's credentials every time they are doing something in the application.

I hope some of this may help!
Was This Post Helpful? 1
  • +
  • -

#3 andrewsw   User is offline

  • Stealth IT
  • member icon

Reputation: 6746
  • View blog
  • Posts: 27,775
  • Joined: 12-December 12

Re: Angular, Identity, with separate API

Posted 15 February 2019 - 07:33 AM

Thank you.

I did something similar, but not entirely. I have a similar UserController and AllowAnonymous method to confirm if logged in/authenticated:

    [Route("api/[controller]")]
    [ApiController]
    public class UserController : Controller
    {
        private readonly IServiceProvider _serviceProvider;

        public UserController(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        [AllowAnonymous]
        [HttpGet("LoggedIn")]
        public ActionResult LoggedIn()
        {
            bool isAuthenticated = User.Identity.IsAuthenticated;
            
            var princical = User as ClaimsPrincipal;
            string name = "";

            bool admin = User.IsInRole("Administrator");

            if (isAuthenticated)
                name = princical.Identity.Name;

            return Json(new { loggedIn = isAuthenticated, userName = name, admin = admin });
        }

I didn't pursue a secret, route guards or HttpInterceptor. I cheated. I just used an Angular service to the above logged-in status, and redirect if this fails:

  ngOnInit() {
    this.authorisedService.LoggedIn()
      .subscribe(log => {
        if (log.loggedIn) {
          this.authorisedService.changeUserName(log.userName);
          this.authorisedService.changeAdminStatus(log.admin);

          this.admin = log.admin;

          if (log.admin) {
            this.getUsers();
            this.getRoles();
          }

        } else {
          this.authorisedService.changeUserName('');
          this.authorisedService.changeAdminStatus(false);

          window.location.href = '/Identity/Account/Login?ReturnUrl=%2Fadmin';
        }
      });
  }

The api controllers (where the important data is) are protected and the admin area is further guarded with an Authorize attribute:

    [Route("api/[controller]")]
    [ApiController]
    [Authorize(Roles = "Administrator")]
    public class AdminController : Controller

I'm not convinced that it is fully locked down, although, whichever way it is approached, data cannot be seen or utilised without being logged in, and the admin area is only accessible to an Administrator.

I've had no assistance at work, and little input or review, but I'm happy with what I personally managed to achieve and learn in the process ;)




I realise in the above code that authorisedService.changeUserName looks a bit odd as it occurs after checking the logged-in status; but the userName is a BehaviourSubject that enables its value to be read and displayed in the navbar.




I notice you put 'currentUser' in localStorage, couldn't that be tampered with effectively?
Was This Post Helpful? 0
  • +
  • -

#4 fearfulsc2   User is offline

  • D.I.C Head

Reputation: 15
  • View blog
  • Posts: 243
  • Joined: 25-May 16

Re: Angular, Identity, with separate API

Posted 15 February 2019 - 07:39 AM

View Postandrewsw, on 15 February 2019 - 07:33 AM, said:

I notice you put 'currentUser' in localStorage, couldn't that be tampered with effectively?


That's where the JWT auth token comes into place for the most part.

If you don't want the user to stay logged in between refreshes or sessions, we could change the behavior by storing user details somewhere less persistent such as session storage or in a property of the authentication service.

Once the user has been logged in, the session can/should be kept open so long as the user does not log out. Of course you can set different parameters in the Token such as how long you want that token to be valid for before the user has to log back in and so forth.
Was This Post Helpful? 1
  • +
  • -

#5 andrewsw   User is offline

  • Stealth IT
  • member icon

Reputation: 6746
  • View blog
  • Posts: 27,775
  • Joined: 12-December 12

Re: Angular, Identity, with separate API

Posted 15 February 2019 - 07:51 AM

I did actually create a branch and follow a detailed tutorial to read and use a Jwt token; that is, to do this properly. I almost got it working and complete (90%) but then a colleague piped in to question whether this was necessary. As I was stuck at that point I just abandoned the branch ;) (but was again happy that I had learnt an amount).

However, I don't have my own custom login page - it redirects to the scaffolded '/Identity/Account/Login?ReturnUrl=%2F' which, I believe, manages the token and a secret - so I kinda sidestepped the issue.

Thanks again.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1