Родитель
7b2a165382
Коммит
fd412df85f
|
@ -1,7 +1,9 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
|
||||
import './App.css';
|
||||
import { Header } from './components/Header';
|
||||
import { Login } from './components/Login';
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
|
@ -21,9 +23,17 @@ getCurrentSample(id)
|
|||
return (
|
||||
<div className="App">
|
||||
<Header />
|
||||
<div className="maincontent">
|
||||
maincontent
|
||||
</div>
|
||||
<Switch>
|
||||
<Route exact path='/' render={() => {
|
||||
return (
|
||||
<div className="maincontent">
|
||||
maincontent
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Route exact path='/login' component={Login} />
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -61,7 +61,8 @@ class Header extends Component {
|
|||
user: {}
|
||||
});
|
||||
userService.getCurrentUser()
|
||||
.then(user => this.setState({ user }));
|
||||
.then(user => this.setState({ user }))
|
||||
.catch(error => console.log(error));
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -70,7 +71,7 @@ class Header extends Component {
|
|||
<div className="headerbar" >
|
||||
<span>
|
||||
<Link styles={linkStyles} href="https://azure.microsoft.com/" target="_blank">Microsoft Azure</Link>
|
||||
{user.firstName !== '' &&
|
||||
{user && user.firstName && user.firstName !== '' &&
|
||||
<Persona
|
||||
styles={personaStyles}
|
||||
text={user.firstName}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
import { Link as FabricLink } from 'office-ui-fabric-react';
|
||||
|
||||
class Login extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
let { from } = this.props.location.state || { from: { pathname: '/' } };
|
||||
|
||||
this.state = {
|
||||
redirectToReferrer: false,
|
||||
from: from
|
||||
};
|
||||
}
|
||||
|
||||
onLogin = () => {
|
||||
let { from } = this.state;
|
||||
window.location = `/api/user/login?returnUrl=${from.pathname}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
let { from, redirectToReferrer } = this.state;
|
||||
|
||||
if (redirectToReferrer) {
|
||||
return <Redirect to={from} />;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<p>You must log in to view the page at {from.pathname}</p>
|
||||
<FabricLink href={`/api/user/login?returnUrl=${from.pathname}`}>Sign in</FabricLink>
|
||||
<br/>
|
||||
<FabricLink href={'/api/user/logout'}>Sign out</FabricLink>
|
||||
<br/>
|
||||
<button onClick={this.onLogin}>Sign in</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export { Login };
|
|
@ -0,0 +1 @@
|
|||
export * from './Login';
|
|
@ -0,0 +1,11 @@
|
|||
export function handleResponse(response) {
|
||||
return response.text().then(text => {
|
||||
const data = text && JSON.parse(text);
|
||||
if (!response.ok) {
|
||||
const error = (data && data.message) || response.statusText;
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
return data;
|
||||
})
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './handle-response';
|
|
@ -1,14 +1,28 @@
|
|||
import { handleResponse } from '../helpers';
|
||||
|
||||
export const userService = {
|
||||
getCurrentUser
|
||||
};
|
||||
|
||||
const dummyUser = {
|
||||
firstName: 'Nehaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
lastName: 'Gupta',
|
||||
fullName: 'Neha Gupta',
|
||||
avatarUrl: 'https://github.com/msnehagup.png'
|
||||
const useFakeApi = true;
|
||||
|
||||
const getFakeUser = () => {
|
||||
return Promise.resolve({
|
||||
fullName: 'Aaaaaaaaaaaaaaaaaaa Bbbbbbbbbbbb',
|
||||
email: 'abc@xyz.com',
|
||||
avatarUrl: 'https://avatars2.githubusercontent.com/u/45184761?v=4',
|
||||
firstName: 'Aaaaaaaaaaaaaaaaaaa'
|
||||
});
|
||||
};
|
||||
|
||||
function getCurrentUser() {
|
||||
return Promise.resolve(dummyUser);
|
||||
if (useFakeApi) {
|
||||
return getFakeUser();
|
||||
}
|
||||
|
||||
const requestOptions = {
|
||||
method: 'GET'
|
||||
};
|
||||
return fetch('/api/user', requestOptions)
|
||||
.then(handleResponse);
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ServerlessLibraryAPI.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
public class SampleDataController : Controller
|
||||
{
|
||||
private static string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
[HttpGet("[action]")]
|
||||
public IEnumerable<WeatherForecast> WeatherForecasts()
|
||||
{
|
||||
var rng = new Random();
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
DateFormatted = DateTime.Now.AddDays(index).ToString("d"),
|
||||
TemperatureC = rng.Next(-20, 55),
|
||||
Summary = Summaries[rng.Next(Summaries.Length)]
|
||||
});
|
||||
}
|
||||
|
||||
public class WeatherForecast
|
||||
{
|
||||
public string DateFormatted { get; set; }
|
||||
public int TemperatureC { get; set; }
|
||||
public string Summary { get; set; }
|
||||
|
||||
public int TemperatureF
|
||||
{
|
||||
get
|
||||
{
|
||||
return 32 + (int)(TemperatureC / 0.5556);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ServerlessLibraryAPI.Models;
|
||||
|
||||
namespace ServerlessLibraryAPI.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
[HttpGet("login"), HttpPost("login")]
|
||||
public IActionResult Login(string returnUrl = "/")
|
||||
{
|
||||
if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
return new RedirectResult(returnUrl);
|
||||
}
|
||||
|
||||
// Instruct the middleware corresponding to the requested external identity
|
||||
// provider to redirect the user agent to its own authorization endpoint.
|
||||
// Note: the authenticationScheme parameter must match the value configured in Startup.cs.
|
||||
// If no scheme is provided then the DefaultChallengeScheme will be used
|
||||
return Challenge(new AuthenticationProperties { RedirectUri = returnUrl });
|
||||
}
|
||||
|
||||
[HttpGet("logout"), HttpPost("logout")]
|
||||
public IActionResult Logout()
|
||||
{
|
||||
// Instruct the cookies middleware to delete the local cookie which
|
||||
// was created after a successful authentication flow.
|
||||
return SignOut(
|
||||
new AuthenticationProperties { RedirectUri = "/" },
|
||||
CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(GitHubUser), 200)]
|
||||
public IActionResult Get()
|
||||
{
|
||||
if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
GitHubUser user = new GitHubUser(User);
|
||||
return Ok(user);
|
||||
}
|
||||
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using System.Security.Claims;
|
||||
using static ServerlessLibraryAPI.OAuth.GitHub.GitHubAuthenticationConstants;
|
||||
|
||||
namespace ServerlessLibraryAPI.Models
|
||||
{
|
||||
public class GitHubUser
|
||||
{
|
||||
public GitHubUser()
|
||||
{
|
||||
}
|
||||
|
||||
public GitHubUser(ClaimsPrincipal claimsPrincipal)
|
||||
{
|
||||
this.FullName = claimsPrincipal.FindFirstValue(Claims.Name);
|
||||
this.Email = claimsPrincipal.FindFirstValue(ClaimTypes.Email);
|
||||
this.AvatarUrl = claimsPrincipal.FindFirstValue(Claims.Avatar);
|
||||
}
|
||||
|
||||
public string FullName { get; set; }
|
||||
|
||||
public string Email { get; set; }
|
||||
|
||||
public string AvatarUrl { get; set; }
|
||||
|
||||
public string FirstName
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.FullName.Split(' ')?[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
namespace ServerlessLibraryAPI.OAuth.GitHub
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains constants specific to the <see cref="GitHubAuthenticationHandler"/>.
|
||||
/// </summary>
|
||||
public static class GitHubAuthenticationConstants
|
||||
{
|
||||
public static class Claims
|
||||
{
|
||||
public const string Name = "urn:github:name";
|
||||
public const string Url = "urn:github:url";
|
||||
public const string Login = "urn:github:login";
|
||||
public const string Avatar = "urn:github:avatar";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
namespace ServerlessLibraryAPI.OAuth.GitHub
|
||||
{
|
||||
/// <summary>
|
||||
/// Default values used by the GitHub authentication middleware.
|
||||
/// </summary>
|
||||
public static class GitHubAuthenticationDefaults
|
||||
{
|
||||
/// <summary>
|
||||
/// Default value for <see cref="AuthenticationScheme.Name"/>.
|
||||
/// </summary>
|
||||
public const string AuthenticationScheme = "GitHub";
|
||||
|
||||
/// <summary>
|
||||
/// Default value for <see cref="AuthenticationScheme.DisplayName"/>.
|
||||
/// </summary>
|
||||
public const string DisplayName = "GitHub";
|
||||
|
||||
/// <summary>
|
||||
/// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>.
|
||||
/// </summary>
|
||||
public const string Issuer = "GitHub";
|
||||
|
||||
/// <summary>
|
||||
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
|
||||
/// </summary>
|
||||
public const string CallbackPath = "/signin-github";
|
||||
|
||||
/// <summary>
|
||||
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
|
||||
/// </summary>
|
||||
public const string AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
|
||||
|
||||
/// <summary>
|
||||
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
|
||||
/// </summary>
|
||||
public const string TokenEndpoint = "https://github.com/login/oauth/access_token";
|
||||
|
||||
/// <summary>
|
||||
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
|
||||
/// </summary>
|
||||
public const string UserInformationEndpoint = "https://api.github.com/user";
|
||||
|
||||
/// <summary>
|
||||
/// Default value for <see cref="GitHubAuthenticationOptions.UserEmailsEndpoint"/>.
|
||||
/// </summary>
|
||||
public const string UserEmailsEndpoint = "https://api.github.com/user/emails";
|
||||
|
||||
/// <summary>
|
||||
/// Scope for <see cref="UserInformationEndpoint"/>.
|
||||
/// </summary>
|
||||
public const string UserInformationScope = "user";
|
||||
|
||||
/// <summary>
|
||||
/// Scope for <see cref="UserEmailsEndpoint"/>.
|
||||
/// </summary>
|
||||
public const string UserEmailsScope = "user:email";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ServerlessLibraryAPI.OAuth.GitHub
|
||||
{
|
||||
public class GitHubAuthenticationHandler : OAuthHandler<GitHubAuthenticationOptions>
|
||||
{
|
||||
public GitHubAuthenticationHandler(
|
||||
IOptionsMonitor<GitHubAuthenticationOptions> options,
|
||||
ILoggerFactory logger,
|
||||
UrlEncoder encoder,
|
||||
ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{
|
||||
}
|
||||
|
||||
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity,
|
||||
AuthenticationProperties properties, OAuthTokenResponse tokens)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
|
||||
|
||||
var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Logger.LogError("An error occurred while retrieving the user profile: the remote server " +
|
||||
"returned a {Status} response with the following payload: {Headers} {Body}.",
|
||||
/* Status: */ response.StatusCode,
|
||||
/* Headers: */ response.Headers.ToString(),
|
||||
/* Body: */ await response.Content.ReadAsStringAsync());
|
||||
|
||||
throw new HttpRequestException("An error occurred while retrieving the user profile.");
|
||||
}
|
||||
|
||||
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
|
||||
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
var context = new OAuthCreatingTicketContext(principal, properties, Context, Scheme, Options, Backchannel, tokens, payload);
|
||||
|
||||
context.RunClaimActions(payload);
|
||||
|
||||
// When the email address is not public, retrieve it from
|
||||
// the emails endpoint if the user:email scope is specified.
|
||||
if (!string.IsNullOrEmpty(Options.UserEmailsEndpoint) &&
|
||||
!identity.HasClaim(claim => claim.Type == ClaimTypes.Email) && Options.Scope.Contains("user:email"))
|
||||
{
|
||||
var address = await GetEmailAsync(tokens);
|
||||
if (!string.IsNullOrEmpty(address))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, address, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
}
|
||||
|
||||
await Options.Events.CreatingTicket(context);
|
||||
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
||||
}
|
||||
|
||||
protected virtual async Task<string> GetEmailAsync(OAuthTokenResponse tokens)
|
||||
{
|
||||
// See https://developer.github.com/v3/users/emails/ for more information about the /user/emails endpoint.
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, Options.UserEmailsEndpoint);
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
|
||||
|
||||
// Failed requests shouldn't cause an error: in this case, return null to indicate that the email address cannot be retrieved.
|
||||
var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Logger.LogWarning("An error occurred while retrieving the email address associated with the logged in user: " +
|
||||
"the remote server returned a {Status} response with the following payload: {Headers} {Body}.",
|
||||
/* Status: */ response.StatusCode,
|
||||
/* Headers: */ response.Headers.ToString(),
|
||||
/* Body: */ await response.Content.ReadAsStringAsync());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var payload = JArray.Parse(await response.Content.ReadAsStringAsync());
|
||||
|
||||
return (from address in payload.AsJEnumerable()
|
||||
where address.Value<bool>("primary")
|
||||
select address.Value<string>("email")).FirstOrDefault();
|
||||
}
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
return base.HandleAuthenticateAsync();
|
||||
}
|
||||
|
||||
protected override Task<HandleRequestResult> HandleRemoteAuthenticateAsync()
|
||||
{
|
||||
return base.HandleRemoteAuthenticateAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using static ServerlessLibraryAPI.OAuth.GitHub.GitHubAuthenticationConstants;
|
||||
|
||||
namespace ServerlessLibraryAPI.OAuth.GitHub
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a set of options used by <see cref="GitHubAuthenticationHandler"/>.
|
||||
/// </summary>
|
||||
public class GitHubAuthenticationOptions : OAuthOptions
|
||||
{
|
||||
public GitHubAuthenticationOptions()
|
||||
{
|
||||
ClaimsIssuer = GitHubAuthenticationDefaults.Issuer;
|
||||
|
||||
CallbackPath = new PathString(GitHubAuthenticationDefaults.CallbackPath);
|
||||
|
||||
AuthorizationEndpoint = GitHubAuthenticationDefaults.AuthorizationEndpoint;
|
||||
TokenEndpoint = GitHubAuthenticationDefaults.TokenEndpoint;
|
||||
UserInformationEndpoint = GitHubAuthenticationDefaults.UserInformationEndpoint;
|
||||
//Scope.Add(GitHubAuthenticationDefaults.UserInformationScope);
|
||||
Scope.Add(GitHubAuthenticationDefaults.UserEmailsScope);
|
||||
|
||||
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Name, "login");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
|
||||
ClaimActions.MapJsonKey(Claims.Name, "name");
|
||||
ClaimActions.MapJsonKey(Claims.Url, "html_url");
|
||||
ClaimActions.MapJsonKey(Claims.Login, "login");
|
||||
ClaimActions.MapJsonKey(Claims.Avatar, "avatar_url");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the address of the endpoint exposing
|
||||
/// the email addresses associated with the logged in user.
|
||||
/// </summary>
|
||||
public string UserEmailsEndpoint { get; set; } = GitHubAuthenticationDefaults.UserEmailsEndpoint;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,14 @@
|
|||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express - API only": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ApiOnly": "true"
|
||||
}
|
||||
},
|
||||
"ServerLessLibrary": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
|
||||
<ApplicationInsightsResourceId>/subscriptions/7c1b7bab-00b2-4cb7-924e-205c4f411810/resourcegroups/Default-ApplicationInsights-EastUS/providers/microsoft.insights/components/ServerlessLibrary</ApplicationInsightsResourceId>
|
||||
<ApplicationInsightsAnnotationResourceId>/subscriptions/7c1b7bab-00b2-4cb7-924e-205c4f411810/resourcegroups/Default-ApplicationInsights-EastUS/providers/microsoft.insights/components/ServerlessLibrary</ApplicationInsightsAnnotationResourceId>
|
||||
<UserSecretsId>235c2497-239d-47f0-8ea7-af2dd2416d95</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace ServerlessLibrary
|
|||
public static string CosmosAuthkey { get { return config(); } }
|
||||
public static string Database { get { return "serverlesslibrary"; } }
|
||||
public static string Collection { get { return "contributions"; } }
|
||||
public static bool ApiOnly { get { return Boolean.Parse(config("false")); } }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ServerlessLibraryAPI.OAuth.GitHub;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
|
||||
namespace ServerlessLibrary
|
||||
|
@ -22,6 +24,20 @@ namespace ServerlessLibrary
|
|||
{
|
||||
services.AddMemoryCache();
|
||||
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultChallengeScheme = GitHubAuthenticationDefaults.AuthenticationScheme;
|
||||
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddCookie()
|
||||
.AddOAuth<GitHubAuthenticationOptions, GitHubAuthenticationHandler>(
|
||||
GitHubAuthenticationDefaults.AuthenticationScheme,
|
||||
GitHubAuthenticationDefaults.DisplayName,
|
||||
options => {
|
||||
options.ClientId = Configuration["Authentication:GitHub:ClientId"]; // these settings need to be present in appSettings (or in secrets.json)
|
||||
options.ClientSecret = Configuration["Authentication:GitHub:ClientSecret"];
|
||||
});
|
||||
|
||||
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
|
||||
|
||||
// In production, the React files will be served from this directory
|
||||
|
@ -56,7 +72,6 @@ namespace ServerlessLibrary
|
|||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseDefaultFiles();
|
||||
app.UseStaticFiles();
|
||||
app.UseSpaStaticFiles();
|
||||
|
@ -67,6 +82,8 @@ namespace ServerlessLibrary
|
|||
c.RoutePrefix = "swagger";
|
||||
});
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute(
|
||||
|
@ -74,15 +91,18 @@ namespace ServerlessLibrary
|
|||
template: "{controller}/{action=Index}/{id?}");
|
||||
});
|
||||
|
||||
app.UseSpa(spa =>
|
||||
if (!ServerlessLibrarySettings.ApiOnly)
|
||||
{
|
||||
spa.Options.SourcePath = "ClientApp";
|
||||
|
||||
if (env.IsDevelopment())
|
||||
app.UseSpa(spa =>
|
||||
{
|
||||
spa.UseReactDevelopmentServer(npmScript: "start");
|
||||
}
|
||||
});
|
||||
spa.Options.SourcePath = "ClientApp";
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
spa.UseReactDevelopmentServer(npmScript: "start");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
|
|
|
@ -5,5 +5,8 @@
|
|||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
},
|
||||
"ApplicationInsights": {
|
||||
"InstrumentationKey": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,5 +7,11 @@
|
|||
"AllowedHosts": "*",
|
||||
"ApplicationInsights": {
|
||||
"InstrumentationKey": "d35b5caf-a276-467c-9ac7-f7f7d84ea171"
|
||||
},
|
||||
"Authentication": {
|
||||
"GitHub": {
|
||||
"ClientId": "",
|
||||
"ClientSecret": ""
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче