Consuming a secured JWT webapi using ionic, angular 2
I had a requirement to create an app which consumes a secured JWT webapi using ionic and angular 2. This is how I did it. Hope you like.
Reference : http://bitoftech.net/2015/02/16/implement-oauth-json-web-tokens-authentication-in-asp-net-web-api-and-identity-2/
1) Open Startup.cs and paste the following code
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler.Encoder;
using Microsoft.Owin.Security.Jwt;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Http;
[assembly: OwinStartup(typeof(SecuredWebAPI.Startup))]
namespace SecuredWebAPI
{
public class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
ConfigureOAuthTokenConsumption(app);
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
//Hosting url
var issuer = "http://localhost:53726";
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider(),
AccessTokenFormat = new CustomJwtFormat("http://localhost:53726") //Hosing Url
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
}
}
2) Create CustomJwtFormat.cs and paste the following code
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler.Encoder;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Web;
using Thinktecture.IdentityModel.Tokens;
namespace SecuredWebAPI
{
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string _issuer = string.Empty;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}
}
3) Open web.config and add the following app settings
<!-- You can modify these if you want -->
<add key="as:AudienceId" value="8866" />
<add key="as:AudienceSecret" value="U2gxMjM0NTY3ODkwMjEyMTIxMjFyZXJlcmVycmVxdGg=" />
Now we will look at the client to consume this web api, I am not going to include all the angular 2 code here. I will just add the service and login codes. Remember you need
angular2-jwt to consume this web api through generated access token.
1) Security.service.ts
import { Injectable } from '@angular/core';
import {Http,Headers} from '@angular/http';
import { AppSettings } from '../app.settings';
import { LoginData,CurrentUserInfo } from '../app.common';
import {Observable} from 'rxjs/Observable';
import { AuthHttp } from 'angular2-jwt';
@Injectable()
export class SecurityService {
public currentUserInfo:CurrentUserInfo;
constructor(private http: Http,private authHttp:AuthHttp) {
this.currentUserInfo = new CurrentUserInfo();
}
login(loginData:LoginData) : any {
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
var credentials = "grant_type=password"
+ "&userName=" + loginData.userName
+ "&password=" + loginData.password;
return this.http.post(AppSettings.API_ENDPOINT +'/token', credentials, { headers: headers });
}
}
2) Login.ts
import { Component, ViewChild } from '@angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SecurityService } from '../../app/services/security.service'
import { LoginData, CurrentUserInfo } from '../../app/app.common'
import { AuthHttp,JwtHelper } from 'angular2-jwt';
import { AppSettings } from '../../app/app.settings';
@Component({
selector:'login',
templateUrl:'login.html',
providers: [SecurityService]
})
export class LoginPage {
private message:string;
private loginData:LoginData;
constructor(private secService:SecurityService,private authHttp:AuthHttp){
this.loginData = new LoginData();
}
login(loginData)
{
this.secService.login(loginData).subscribe((res) => {
var resObj = res.json();
if (typeof resObj.access_token != "undefined")
{
this.secService.currentUserInfo.isLoggedIn = true;
localStorage.setItem('access_token',resObj.access_token);
var jwtHelper = new JwtHelper();
localStorage.setItem('loginKey',jwtHelper.decodeToken(resObj.access_token).loginKey);
this.message = "Successfull Login";
this.authHttp.get(AppSettings.API_ENDPOINT +'/api/User/GetFunctions?loginKey='+localStorage.getItem('loginKey'))
.subscribe((res)=> {console.log(res);});
}
else
{
this.secService.currentUserInfo.isLoggedIn = false;
this.message = "login Failed!!! "+
JSON.parse(resObj._body).error_description;
}
},(error)=>{
this.secService.currentUserInfo.isLoggedIn = false;
this.message = "login Failed!!! "+ error;
});
}
}
Reference : http://bitoftech.net/2015/02/16/implement-oauth-json-web-tokens-authentication-in-asp-net-web-api-and-identity-2/
1) Open Startup.cs and paste the following code
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler.Encoder;
using Microsoft.Owin.Security.Jwt;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Http;
[assembly: OwinStartup(typeof(SecuredWebAPI.Startup))]
namespace SecuredWebAPI
{
public class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
ConfigureOAuthTokenConsumption(app);
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
//Hosting url
var issuer = "http://localhost:53726";
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider(),
AccessTokenFormat = new CustomJwtFormat("http://localhost:53726") //Hosing Url
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
}
}
2) Create CustomJwtFormat.cs and paste the following code
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.DataHandler.Encoder;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Web;
using Thinktecture.IdentityModel.Tokens;
namespace SecuredWebAPI
{
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string _issuer = string.Empty;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}
}
3) Open web.config and add the following app settings
<!-- You can modify these if you want -->
<add key="as:AudienceId" value="8866" />
<add key="as:AudienceSecret" value="U2gxMjM0NTY3ODkwMjEyMTIxMjFyZXJlcmVycmVxdGg=" />
Now we will look at the client to consume this web api, I am not going to include all the angular 2 code here. I will just add the service and login codes. Remember you need
angular2-jwt to consume this web api through generated access token.
1) Security.service.ts
import { Injectable } from '@angular/core';
import {Http,Headers} from '@angular/http';
import { AppSettings } from '../app.settings';
import { LoginData,CurrentUserInfo } from '../app.common';
import {Observable} from 'rxjs/Observable';
import { AuthHttp } from 'angular2-jwt';
@Injectable()
export class SecurityService {
public currentUserInfo:CurrentUserInfo;
constructor(private http: Http,private authHttp:AuthHttp) {
this.currentUserInfo = new CurrentUserInfo();
}
login(loginData:LoginData) : any {
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
var credentials = "grant_type=password"
+ "&userName=" + loginData.userName
+ "&password=" + loginData.password;
return this.http.post(AppSettings.API_ENDPOINT +'/token', credentials, { headers: headers });
}
}
2) Login.ts
import { Component, ViewChild } from '@angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SecurityService } from '../../app/services/security.service'
import { LoginData, CurrentUserInfo } from '../../app/app.common'
import { AuthHttp,JwtHelper } from 'angular2-jwt';
import { AppSettings } from '../../app/app.settings';
@Component({
selector:'login',
templateUrl:'login.html',
providers: [SecurityService]
})
export class LoginPage {
private message:string;
private loginData:LoginData;
constructor(private secService:SecurityService,private authHttp:AuthHttp){
this.loginData = new LoginData();
}
login(loginData)
{
this.secService.login(loginData).subscribe((res) => {
var resObj = res.json();
if (typeof resObj.access_token != "undefined")
{
this.secService.currentUserInfo.isLoggedIn = true;
localStorage.setItem('access_token',resObj.access_token);
var jwtHelper = new JwtHelper();
localStorage.setItem('loginKey',jwtHelper.decodeToken(resObj.access_token).loginKey);
this.message = "Successfull Login";
this.authHttp.get(AppSettings.API_ENDPOINT +'/api/User/GetFunctions?loginKey='+localStorage.getItem('loginKey'))
.subscribe((res)=> {console.log(res);});
}
else
{
this.secService.currentUserInfo.isLoggedIn = false;
this.message = "login Failed!!! "+
JSON.parse(resObj._body).error_description;
}
},(error)=>{
this.secService.currentUserInfo.isLoggedIn = false;
this.message = "login Failed!!! "+ error;
});
}
}
Comments
Post a Comment