Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ClientApp/@types/alltypes.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'EventEmitter';
1 change: 1 addition & 0 deletions ClientApp/assets/loading.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 78 additions & 0 deletions ClientApp/auth/AuthService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import auth0, { WebAuth } from 'auth0-js'
import router from '../router/'
import EventEmitter from 'EventEmitter'

export default class AuthService {
authenticated = this.isAuthenticated()
authNotifier = new EventEmitter()
auth0: WebAuth
constructor(hostname:string, port:string, protocol:string) {
this.login = this.login.bind(this);
this.setSession = this.setSession.bind(this)
this.logout = this.logout.bind(this)
this.isAuthenticated = this.isAuthenticated.bind(this)
var stringBuild = protocol + "//" + hostname;
if (port !== "")
stringBuild += ':' + port
stringBuild += '/callback'
this.auth0 = new auth0.WebAuth({
domain: 'dotnextrussia.eu.auth0.com',
clientID: 'g7saZcm47evyY3kWWP26ZxifDpxycl9h',
redirectUri: stringBuild,
audience: 'http://medhelp20171124063439.azurewebsites.net/',
responseType: 'token id_token',
scope: 'openid profile read:templates'
});
}




login() {
this.auth0.authorize();
}

handleAuthentication () {
this.auth0.parseHash((err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
this.setSession(authResult)
router.replace('home')
} else if (err) {
router.replace('home')
console.log(err)
alert(`Error: ${err.error}. Check the console for further details.`)
}
location.reload()
})
}

setSession (authResult : any) {
// Set the time that the access token will expire at
let expiresAt = JSON.stringify(
authResult.expiresIn * 1000 + new Date().getTime()
)
localStorage.setItem('access_token', authResult.accessToken)
localStorage.setItem('id_token', authResult.idToken)
localStorage.setItem('expires_at', expiresAt)
this.authNotifier.emit('authChange', { authenticated: true })
}

logout () {
// Clear access token and ID token from local storage
localStorage.removeItem('access_token')
localStorage.removeItem('id_token')
localStorage.removeItem('expires_at')
//this.userProfile = null
this.authNotifier.emit('authChange', false)
// navigate to the home route
router.replace('home')
location.reload()
}

isAuthenticated () {
// Check whether the current time is past the
// access token's expiry time
let expiresAt = JSON.parse(localStorage.getItem('expires_at') || '{}')
return new Date().getTime() < expiresAt
}
}
9 changes: 3 additions & 6 deletions ClientApp/boot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ import './css/site.css';
import 'bootstrap';
import Vue from 'vue';
import VueRouter from 'vue-router';
import router from './router'
import App from './components/app/app'
Vue.use(VueRouter);

const routes = [
{ path: '/', component: require('./components/home/home.vue.html') },
{ path: '/counter', component: require('./components/counter/counter.vue.html') },
{ path: '/fetchdata', component: require('./components/fetchdata/fetchdata.vue.html') }
];

new Vue({
el: '#app-root',
router: new VueRouter({ mode: 'history', routes: routes }),
router: router,
render: h => h(require('./components/app/app.vue.html'))
});
27 changes: 23 additions & 4 deletions ClientApp/components/app/app.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
import Vue from 'vue';
import { Component } from 'vue-property-decorator';
import AuthService from '../../auth/AuthService';

@Component({


const auth = new AuthService(window.location.hostname, window.location.port, window.location.protocol)

var { login, logout, authenticated, authNotifier } = auth

export default Vue.extend({
name: 'app',
components: {
MenuComponent: require('../navmenu/navmenu.vue.html')
},
data() {
authNotifier.on('authChange', (authState:any) => {
authenticated = authState.authenticated
})
return {
auth,
authenticated
}
},
methods: {
login,
logout
}
})
export default class AppComponent extends Vue {
}
})
8 changes: 7 additions & 1 deletion ClientApp/components/app/app.vue.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
<div class="row">
<div class="col-sm-3">
<menu-component />

</div>
<div class="col-sm-9">
<router-view></router-view>
<router-view
:auth="auth"
:authenticated="authenticated">
</router-view>
</div>
</div>

</div>

</template>

<script src="./app.ts"></script>
11 changes: 11 additions & 0 deletions ClientApp/components/callback/callback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Vue from "vue";

export default Vue.extend({
name: 'callback',
props: ['auth'],
data () {
// alert(JSON.stringify(this.auth))
this.auth.handleAuthentication()
return {}
}
})
20 changes: 20 additions & 0 deletions ClientApp/components/callback/callback.vue.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<template>
<div class="spinner">
<img src="../../assets/loading.svg" alt="loading"/>
</div>
</template>

<style>
.spinner {
position: absolute;
display: flex;
justify-content: center;
height: 100vh;
width: 100vw;
background-color: white;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
27 changes: 21 additions & 6 deletions ClientApp/components/fetchdata/fetchdata.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Vue from 'vue';
import { Component } from 'vue-property-decorator';
import axios from 'axios';


interface WeatherForecast {
dateFormatted: string;
Expand All @@ -11,12 +13,25 @@ interface WeatherForecast {
@Component
export default class FetchDataComponent extends Vue {
forecasts: WeatherForecast[] = [];

HTTP = axios.create({
baseURL: 'api/SampleData/WeatherForecasts',

})
mounted() {
fetch('api/SampleData/WeatherForecasts')
.then(response => response.json() as Promise<WeatherForecast[]>)
.then(data => {
this.forecasts = data;
});
axios.get("api/SampleData/WeatherForecasts",
{
headers: {
Authorization: 'Bearer ' + localStorage.getItem('access_token')
}
})
.then(response => {
this.forecasts = response.data
})
.catch(e => {
alert(e)
})

// fetch('api/SampleData/WeatherForecasts')

}
}
5 changes: 5 additions & 0 deletions ClientApp/components/home/home.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Vue from 'vue';
export default Vue.extend({
name: 'home',
props: ['auth', 'authenticated']
})
42 changes: 26 additions & 16 deletions ClientApp/components/home/home.vue.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
<template>
<div>
<h1>Hello, world!</h1>
<p>Welcome to your new single-page application, built with:</p>
<ul>
<li><a href="https://get.asp.net/">ASP.NET Core</a> and <a href="https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx">C#</a> for cross-platform server-side code</li>
<li><a href="https://vuejs.org/">Vue.js</a> and <a href="http://www.typescriptlang.org/">TypeScript</a> for client-side code</li>
<li><a href="https://webpack.github.io/">Webpack</a> for building and bundling client-side resources</li>
<li><a href="http://getbootstrap.com/">Bootstrap</a> for layout and styling</li>
</ul>
<p>To help you get started, we've also set up:</p>
<ul>
<li><strong>Client-side navigation</strong>. For example, click <em>Counter</em> then <em>Back</em> to return here.</li>
<li><strong>Webpack dev middleware</strong>. In development mode, there's no need to run the <code>webpack</code> build tool. Your client-side resources are dynamically built on demand. Updates are available as soon as you modify any file.</li>
<li><strong>Hot module replacement</strong>. In development mode, you don't even need to reload the page after making most changes. Within seconds of saving changes to files, your Vue app will be rebuilt and a new instance injected is into the page.</li>
<li><strong>Efficient production builds</strong>. In production mode, development-time features are disabled, and the <code>webpack</code> build tool produces minified static CSS and JavaScript files.</li>
</ul>
<h1 v-if="authenticated">Здравствуй, врач! Система скоро будет готова!</h1>
<div>
<h4 v-if="authenticated">
Вы вошли в систему!
</h4>
<h4 v-if="!authenticated">
Вы не вошли в систему! Пожалуйста, <a @click="auth.login()">войдите</a> чтобы продолжить.
</h4>
<button
class="btn btn-primary btn-margin"
v-if="authenticated"
@click="auth.logout()">
Выйти
</button>

</div>
</div>
</template>

</template>


<style>
a {
cursor: pointer;
}
</style>
<script src="./home.ts" />
31 changes: 31 additions & 0 deletions ClientApp/router/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../components/home/home'
import Callback from '../components/callback/callback'

Vue.use(Router)

const router = new Router({
mode: 'history',
routes: [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/callback',
name: 'Callback',
component: Callback
},
{
path: '*',
redirect: '/home'
},
{ path: '/', component: require('../components/home/home.vue.html') },
{ path: '/counter', component: require('../components/counter/counter.vue.html') },
{ path: '/fetchdata', component: require('../components/fetchdata/fetchdata.vue.html') }
]
})

export default router
2 changes: 2 additions & 0 deletions Controllers/SampleDataController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace MedHelp.Controllers
Expand All @@ -14,6 +15,7 @@ public class SampleDataController : Controller
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

[Authorize]
[HttpGet("[action]")]
public IEnumerable<WeatherForecast> WeatherForecasts()
{
Expand Down
13 changes: 11 additions & 2 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,18 @@ public static void Main(string[] args)
BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
public static IWebHost BuildWebHost(string[] args)
{
#if DEBUG
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseUrls("http://localhost:5000/")
.Build();
#else
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
#endif
}
}
}
27 changes: 27 additions & 0 deletions ScopeMiddleware/HasScopeHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;

namespace MedHelp.ScopeMiddleware
{
public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
HasScopeRequirement requirement)
{
// If user does not have the scope claim, get out of here
if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
return Task.CompletedTask;

// Split the scopes string into an array
var scopes = context.User.FindFirst(c => c.Type == "scope" && c.Issuer == requirement.Issuer).Value
.Split(' ');

// Succeed if the scope array contains the required scope
if (scopes.Any(s => s == requirement.Scope))
context.Succeed(requirement);

return Task.CompletedTask;
}
}
}
Loading