Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Friday, May 03, 2019

Vanilla JavaScript for the Client Side of my JWT Server App

This is the Vanilla JavaScript client side code to accompany JWT on .NET Core 2.2 and Little Else. I have the sourcecode on my Github account as a branch of the other project.

Logging in (as far as it goes)

To log in, I need to make a request to my services with the data gathered from my “login” form. The request is a POST and the in sent to the server as JSON (“content-Type:application/json” in the head. When I get a response back from the server, XMLHttpRequest calls getJwtProcessResponse():

function getJwt() {
  showResults("working ....");

  // Assemble data to log in, should match schema of MakeTokenViewModel
  const userName = document.getElementById("txtUserName").value;
  const role = document.getElementById("txtRole").value;
  const id = document.getElementById("txtId").value;
  const fail = document.getElementById("chkFail").checked;
  const message = 
    `{"UserName":"${userName}","Role": "${role}","Id": ${id},"Fail":${fail}}`;

  // Make the request
  const xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = getJwtProcessResponse;
  xhttp.open("Post", `${BASE_URL}jwt/maketoken`, true);
  xhttp.setRequestHeader("content-Type", "application/json");
  xhttp.send(message);
}

When I get a response back and it’s ready: if the status is 200, login succeeded, and I store the JWT in Local Storage with writeJwt() (since I’m not sending anything other than the JWT, I don’t have to parse it out of this.responseText). Otherwise, alert the user of the failure.

// Get and process the request
function getJwtProcessResponse() {
  if (this.readyState == 4) {
    if (this.status == 200) {
      writeJwt(this.responseText);
      showResults("token written to localStorage");
    }
    else {
      alert(`${this.status}\n ${this.responseText}`);
        showResults("Failed!");
    }
  }
}

Making a call to the Service

Here I am going to make a simple GET request with the JWT in Local Storage (if available)

// Make a call to the end point specified by urlExtension
// (each endpoint has a different permission, for demo purpose)
function makeCall(urlExtension) {
  showResults("working ....");
  const jwt = readJwt();
  const xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = makeCallProcessResponse;
  xhttp.open("Get", `${BASE_URL}values${urlExtension}`, true);
  // We want to test with the user not logged in
  if (!!jwt) {
      xhttp.setRequestHeader("Authorization", ` Bearer  ${jwt}`);
  }
  xhttp.send();
}

When I get a response back and it’s ready: if the status is 200, I am authorized to and call showResults() to show what I got back. Otherwise the user is alerted about the failure

function makeCallProcessResponse() {
  if (this.readyState == 4) {
    if (this.status == 200) {
      showResults(this.responseText);
    }
    else {
      alert(`${this.status}\n ${this.responseText}`);
      showResults("Failed!");
    }
  }
}

Logging out

You really don’t log off JWT, they expire. To simulate logging out of a site, you make Local Storage forget:

function deleteJwt() {
  clearJwt();
}

Reading JWT “payload”

You can embed data in middle part of the JWT (the Payload) as unencrypted Base64 encoded JSON (Yes, I stole it from StackOverflow).

//see https://stackoverflow.com/a/38552302/3819
function parseJwt(token) {
  const base64Url = token.split('.')[1];
  const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
  return JSON.parse(window.atob(base64));
}

The localStorage functions

These are the functions that actually read and write the JWT to localStorage:

function writeJwt(jwt) {
  if (typeof Storage !== "undefined") {
    localStorage.setItem("jwt", jwt);
  } else {
    showResults("Sorry, your browser does not support Web Storage...")
  }
}

function readJwt() {
  if (typeof Storage !== "undefined") {
    return localStorage.getItem("jwt");
  } else {
    showResults("Sorry, your browser does not support Web Storage...");
  }
  return "";
}

function clearJwt() {
  if (typeof Storage !== "undefined") {
    localStorage.removeItem("jwt");
  } else {
    showResults("Sorry, your browser does not support Web Storage...");
  }
}

The Whole Page

And here is the whole page (JS, CSS and HTML all in one):

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 25px;
    }

    label {
      width: 80px;
      display: inline-block;
      margin: 2px;
    }

    input {
      margin: 2px;
    }

    button {
      width: 150px;
      margin: 2px;
    }

    #result {
      width: 100%;
      height: 150px;
    }
    .grid-container {
      width: 100%;
      display: grid;
      grid-gap: 10px;
      grid-template-columns: 1fr 1fr 1fr;
    }

    .grid-container {
      display: inline-grid;
    }
  </style>
</head>
<body>
  <h2>JWT Client</h2>
  <div id="theGrid"class="grid-container">
    <div id="data"class="grid-item" >
      <h3>Data for JWT</h3>
      <p>This is the data used to create the JWT. The Server recognizes 2 roles: "admin" and "super".</p>
      <p>(We can simulate a log in failure by checking "Fail")</p>
      <label for="txtUserName">User Name </label><input type="text" id="txtUserName" value="johns" /><br />
      <label for="txtRole">Role</label><input type="text" id="txtRole" value="admin" /><br />
      <label for="txtId">Id</label><input type="number" id="txtId" value="42" /><br />
      <label for="chkFail">Fail</label><input type="checkbox" id="chkFail" value="false" /><br />
    </div>
    <div id="access" class="grid-item">
      <h3>Make JWT</h3>
      <p>Here we get the JWT from the "server", store and retrieve the JWT.</p>
      <p>The JWT is stored in Local Storage.</p>
      <button type="button" onclick="getJwt()">Get Token</button><br />
      <button type="button" onclick="showJwt()">Show Token</button><br />
      <button type="button" onclick="decode()">Decode</button><br />
      <button type="button" onclick="deleteJwt()">Clear Token</button><br />
    </div>
    <div id="use" class="grid-item">
      <h3>Use JWT</h3>
      <p>Here we use the JWT we stored in Local Storage and make calls to       
      various endpoints which have different permissions on the server</p>
      <p>The Server decodes the claims in the JWT and returns them as JSON object</p>
      <button type="button" onclick="makeCall('')">Call "/"</button><br />
      <button type="button" onclick="makeCall('/admin')">Call "/admin"</button><br />
      <button type="button" onclick="makeCall('/super')">Call "/super"</button><br />
      <button type="button" onclick="makeCall('/either')">Call "/either"</button><br />
      <button type="button" onclick="makeCall('/open')">Call "/open"</button><br />
    </div>
  </div>
  <div id="results">
    <label for="result">Results</label><br />
    <textarea id="result"></textarea>
  </div>
  <script>
    const BASE_URL = "/api/";
    function getJwt() {
      showResults("working ....");

      // Assemble data to log in, should match schema of MakeTokenViewModel
      const userName = document.getElementById("txtUserName").value;
      const role = document.getElementById("txtRole").value;
      const id = document.getElementById("txtId").value;
      const fail = document.getElementById("chkFail").checked;
      const message = `{"UserName":"${userName}","Role": "${role}","Id": ${id},"Fail":${fail}}`;

      // Make the request
      const xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = getJwtProcessResponse;
      xhttp.open("Post", `${BASE_URL}jwt/maketoken`, true);
      xhttp.setRequestHeader("content-Type", "application/json");
      xhttp.send(message);
    }

    // Get and process the request
    function getJwtProcessResponse() {
      if (this.readyState == 4) {
        if (this.status == 200) {
          writeJwt(this.responseText);
          showResults("token written to localStorage");
        }
        else {
          alert(`${this.status}\n ${this.responseText}`);
          showResults("Failed!");
        }
      }
    }

    // Make a call to the end point specified by urlExtension
    // (each endpoint has a different permission, for demo purpose)
    function makeCall(urlExtension) {
      showResults("working ....");
      const jwt = readJwt();
      const xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = makeCallProcessResponse;
      xhttp.open("Get", `${BASE_URL}values${urlExtension}`, true);
      // We want to test with the user not logged in
      if (!!jwt) {
        xhttp.setRequestHeader("Authorization", ` Bearer  ${jwt}`);
      }
      xhttp.send();
    }

    function makeCallProcessResponse() {
      if (this.readyState == 4) {
        if (this.status == 200) {
          showResults(this.responseText);
        }
        else {
          alert(`${this.status}\n ${this.responseText}`);
          showResults("Failed!");
        }
      }
    }

    function showJwt() {
      const jwt = readJwt();
      if (jwt === null) {
        showResults("no token to display");
        return;
      }
      showResults(jwt);
    }

    function deleteJwt() {
      clearJwt();
    }

    function writeJwt(jwt) {
      if (typeof Storage !== "undefined") {
        localStorage.setItem("jwt", jwt);
      } else {
        showResults("Sorry, your browser does not support Web Storage...")
      }
    }

    function readJwt() {
      if (typeof Storage !== "undefined") {
        return localStorage.getItem("jwt");
      } else {
        showResults("Sorry, your browser does not support Web Storage...");
      }
      return "";
    }

    function clearJwt() {
      if (typeof Storage !== "undefined") {
        localStorage.removeItem("jwt");
      } else {
        showResults("Sorry, your browser does not support Web Storage...");
      }
    }

    function decode() {
      const jwt = readJwt();
      if (jwt == null) {
        showResults("no token to decode");
        return;
      }
      const parsed = parseJwt(jwt);
      showResults(JSON.stringify(parsed, null, 2));
    }

    //see https://stackoverflow.com/a/38552302/3819
    function parseJwt(token) {
      const base64Url = token.split('.')[1];
      const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
      return JSON.parse(window.atob(base64));
    };

    function showResults(results) {
      document.getElementById("result").value = results;
    }
  </script>
</body>
</html>

Monday, July 23, 2018

AngularJS vs Angular: index.html and boostrapping

This is part of a series that compares AngularJS (the old Angular) to Angular.

For the first comparison, I’m going to look at index.html and how the apps are set up or bootstrapped.

AngularJS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html ng-app="mainModule">
<head>
  <title>TasksA1</title>
  <script src="https://code.angularjs.org/1.7.0/angular.min.js"></script>
  <script src="https://code.angularjs.org/1.7.0/angular-resource.min.js"></script>
  <script src="https://code.angularjs.org/1.7.0/angular-route.js"></script>
  <script src="app.js"></script>  
  <script src="app-routing.module.js"></script>
  <script src="services/todo.service.js"></script>
  <script src="pages/home/home.component.js"></script>
  <script src="pages/to-do-list/to-do-list.component.js"></script>
  <script src="pages/to-do-item/to-do-item.component.js"></script>
  <!-- Angular CLR project somehow adds Boostrap into the file -->
  <link rel="stylesheet" 
  href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" 
  integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" 
  crossorigin="anonymous">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <h1>ToDos using AngularJS (1)</h1>
  <a href="#!/toDoList">ToDos</a>
  |
  <a href="#!/toDoAdd">New ToDo</a>
  <div ng-view></div>
</body>
</html>
index.html

On line 2, there is the ng-app directive, telling AngularJS to do its magic. Lines 5-13 there are script tags, first Angulars then mine. Then on line 26 we have a div with a ng-view directive, that's where all the magic happens.

Angluar

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>TasksA6Ts</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <h1>ToDos using Angular /w TypeScript</h1>
  <a href="/toDoList">ToDos</a>
  |
  <a href="/toDoAdd">New ToDo</a>
  <app-root></app-root>
</body>
</html>
index.html

The app-root tag replaces the div with the ng-view directive. There is no ng-app directive or script tags. When I did a view source. But how does it know which files to insert; I think it gets them from app.module.ts (the files are reduced to ES5 and dumped into a single file).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { ReactiveFormsModule , FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ToDoItemComponent } from './pages/to-do-item/to-do-item.component';
import { ToDoListComponent } from './pages/to-do-list/to-do-list.component';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { HomeComponent } from './pages/home/home.component';

@NgModule({
  declarations: [
    AppComponent,
    ToDoItemComponent,
    ToDoListComponent,
    HomeComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ReactiveFormsModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
app.module.ts

These are the files in the actual project, but an Angular app needs to be built. I built the app with the command ng build and when I look at the build results and this is the generated index.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>TasksA6Ts</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <h1>ToDos using Angular /w TypeScript</h1>
  <a href="/toDoList">ToDos</a>
  |
  <a href="/toDoAdd">New ToDo</a>
  <app-root></app-root>
<script type="text/javascript" src="runtime.js"></script>
<script type="text/javascript" src="polyfills.js"></script>
<script type="text/javascript" src="styles.js"></script>
<script type="text/javascript" src="vendor.js"></script>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
Generated index.html

All of the TypeScript files mentioned in app.module.ts are transpiled into ES5 into main.js

About the series AngularJS vs Angular


AngularJS vs Angular: The Introduction

As I try to maintain my status as a “Full Stack Developer” I have been looking at Angular and AngularJS. So, what gives? Angular is an open source web application platform that Google released in 2016 to replace AngularJS (then called Angular). AngularJS is Google’s original Angular, released in 2010. Angular and AngularJS are completely different.

In this experiment I wrote a simple list/detail site in both AngularJS (in JavaScript ES5) and Angular (in TypeScript). I created a simple REST endpoint with JSON-Server.

Methodology

AngularJS

I took a project I wrote a coupe of years ago and simplified it and then refactored it to match the files structure of the Angular app (foo.ts became foo.js).

Angular

I created the app, the components and services using the Angular CLI (version 6). I put all of the REST calls in a “services” to match the architecture I used in the AngularJS app; most of the samples I found online called the http methods directly from the components.

The App

The Task List is the “Hello World” of databinding, so I went with this. I dropped the “People” table so we only have 1 table: “Todos”. Both apps do the same thing using the same structure as far as I could push it.

About the series AngularJS vs Angular

Tuesday, January 29, 2013

WinRT CS vs JS: Grids

C# XAML

In XAML, a grid is pretty straight forward. Within the Grid tag, you define the rows and column in RowDefinitions and ColumnDefinitions tags. Below the definitions, you place the controls that will reside in the Grid, you assign them to cells and control cell spans with Row. attributes.

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="1*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="1*"/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">Title</TextBlock>
    <TextBlock Grid.Row="1" Grid.Column="0">2, 1</TextBlock>
    <TextBlock Grid.Row="1" Grid.Column="1">2, 2</TextBlock>
    <TextBlock Grid.Row="1" Grid.Column="2">2, 3</TextBlock>
    <TextBlock Grid.Row="2" Grid.Column="0">3, 1</TextBlock>
    <TextBlock Grid.Row="2" Grid.Column="1">3, 2</TextBlock>
    <TextBlock Grid.Row="2" Grid.Column="2">3, 3</TextBlock>
</Grid>

This is straight forward; the WinJS examples will attempt to match this layout.

JavaScript HTML


In WinJS, a grid is achieved using an IE 10 specific version of the CSS Grid Layout. Since this is CSS, you can select HTML elements using id or class selectors, you can even use inline styles. In this example, I will mix in all three. Basically you:

Create a style for the grid, in that style you need to tell it to display as a grid with a display attribute with the value -ms-grid.

Define the columns with a -ms-grid-columns property (“1fr” means 1 fraction value, behaves like 1* in XAML, see table below).

Define the rows with a -ms-grid-rows property.

You can assign an HTML element to a row with a -ms-grid-row and to a column with a -ms-grid-column. I have been playing with the idea of creating a class for each row and column/

With this in mind, I created the following CSS (put in css/default.css, if you want to do this yourself):

#MainGrid {
    display: -ms-grid;
    -ms-grid-columns: 1fr 1fr 1fr;
    -ms-grid-rows: 1fr 1fr 1fr;
    height: 100%; /* make it big, so we can see it */
}
.Col01 {
    -ms-grid-column: 1;
}
.Col02 {
    -ms-grid-column: 2;
}
.Col03 {
    -ms-grid-column: 3;
}
.Row01 {
    -ms-grid-row: 1;
}
.Row02 {
    -ms-grid-row: 2;
}
.Row03 {
    -ms-grid-row: 3;
}

OK, so you have some styles, but you can’t see styles. You need some HTML markup to receive the styles.

At this early stage in my WInJS development, it makes sense to me to style the main grid using an ID selector, so I’m calling the main grid div “MainGrid”. Each grid is going to be unique.

For row and column assignment I am using the ColXX and RowXX classes. To me is as easy to read as XAML’s Grid.Row=”0” and you can avoid creating ids for every cell in every cell in your application.

And I’m using the inline style on the first row to force it to span the 3 columns. I was debating using a class called “ColSpan03” but this gave me the opportunity to demonstrate an inline style.

With all this in mind, here’s the HTML for my grid (put in the body of default.html, if you are playing along at home):

<div id="MainGrid" >
    <div class="Col01 Row01" style="-ms-grid-column-span: 3">Title</div>
    <div class="Col01 Row02">2, 1</div>
    <div class="Col02 Row02">2, 2</div>
    <div class="Col03 Row02">2, 3</div>
    <div class="Col01 Row03">3, 1</div>
    <div class="Col02 Row03">3, 2</div>
    <div class="Col03 Row03">3, 3</div>
</div>

Comparing units in Row and Column Definitions


Here is a list of the various units that can be used to define the sized of rows and columns.


Purpose XAML WinJS Notes
Fractional Units * so 1 fractional unit would be “1*”, 2 would be 2* and so on fr so 1 fractional unit would be “1fr”, 2 would be “2fr” and so on  
Auto Sizing “auto” “auto” Although they are the same keyword, they behave slightly differently,
WinJS is more willing to wrap text and XAML is more likely to scroll
Percent Not supported % so fifty percent would be “50%” For XAML, you could use Fractional Units that add up to 100
Pixels Just the number, so 20 pixels would be “20” px, so 20 pixels would be 20px  
Inches Not supported in  
Centimeters Not supported cm  
Millimeters Not supported mm  
Points Not supported pt  

Saturday, January 26, 2013

WinRT CS vs JS: Events

Without events, it is imposable for the user to interact with the program. So, for this comparison I am going to wire up a simple click event (_btnUpdateText_Click()) that changes the text on a label (_txtHelloText) with the value of an integer that counts clicks (_clickNo). The sample is mind numbly simple to make the differences as stark as possible. I am using the same names where possible in both C# and JavaScript. So here goes:

Javascript HTML

  1. Create a JavaScript Windows Store Blank App, I’m calling mine “simpleEventJS”
  2. Open up default.html and paste the following on top of the existing body tag:
    <body>
    <h1>Simple Events</h1>
    <div id="_txtHelloText">Button is still Unclicked</div>
    <button id="_btnUpdateText">Click Me</button>
    </body>
    

  3. Open js/default.js
  4. Insert the following code just above the call to app.start();:
    // Just for proofiness, I will keep track of clicks and display in the event
    var _clickNo = 0;
    
    function _btnUpdateText_Click() {
    "use strict";
    var control = document.getElementById("_txtHelloText");
    control.innerText = "Click #" + (++_clickNo);
    }
    

  5. Replace args.setPromise(WinJS.UI.processAll()); with the following code:
    args.setPromise(WinJS.UI.processAll().done(function () {
    var button1 = document.getElementById("_btnUpdateText");
    button1.addEventListener("click", _btnUpdateText_Click, false);
    })
    );
    

NOTE: On wiring the event, my first instinct would to wire it in the markup (onclick="_btnUpdateText_Click"). Experts recommend that you don’t do that, besides, if you put the event handler in js/default.js, it would be out of scope anyway. I suppose you could imbed the JavaScript in the markup, but that stinks too.

C# XAML

  1. Create a Visual Studio C# Windows Store Blank App (XAML), I’m calling mine “simpleEventCS”
  2. Open MainPage.xaml and paste the following on top of the existing Grid tag (I am using the StackPanel to get it to be more similar to the JS sample above):
    <StackPanel Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <TextBlock>Simple Events</TextBlock>
    <TextBlock Name="_txtHelloText">Button is still Unclicked</TextBlock>
    <Button Name="_btnUpdateText" Click="_btnUpdateText_Click">Click Me</Button>
    </StackPanel>
    

  3. Double click on “_btnUpdateText_Click” in the Button tag
  4. Right click on the highlighted text and select Navigate to Event Handler
  5. Visual Studio will open MainPage.xaml.cs and create an empty even handler named _btnUpdateText_Click, replace that handler (all the way to the first closing bracket ‘}’) with:
    // Just for proofiness, I will keep track of clicks and display in the event
    private int _clickNo = 0;
    
    private void _btnUpdateText_Click(object sender, RoutedEventArgs e)
    {
    _txtHelloText.Text = "Click #" + (++_clickNo).ToString();
    }
    

NOTE: Yes, the UI for this sample is ugly compared the JavaScript sample above; this is what I get with no styling. It would violate my brain dead simple rule.