I created asp.net core with React template in VS 2019, i need to authorize a controller method so I first registered my app on Azure AD and than i used this Startup.cs configurations:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
services.AddControllersWithViews().AddMicrosoftIdentityUI();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
In the controller I used AuthorizeForScopes and ITokenAcquisition as follows
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ITokenAcquisition tokenAcquisition;
public WeatherForecastController(ITokenAcquisition tokenAcquisition)
{
this.tokenAcquisition = tokenAcquisition;
}
[AuthorizeForScopes(Scopes = new[] { "https://tenantname.sharepoint.com/AllSites.FullControl" })]
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
string accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(new[] { "https://tenantname.sharepoint.com/AllSites.FullControl" });
......
......
}
}
but when i try to fetch the data i have a CORS error
Can you help me
Regarding the issue, please refer to the following steps
Register client application and server application
Use React project template with ASP.NET Core
Client application
a. Install msal
npm install msal
b. Define MsalAuthProvider.
import React, { Component } from 'react';
import { UserAgentApplication } from 'msal';
const msalConfig = {
authority: 'https://login.microsoftonline.com/common',
clientId: '232a1406-b27b-4667-b8c2-3a865c42b79c',
redirectUri: document.getElementById('root').baseURI
};
export const msalAuth = new UserAgentApplication({
auth: msalConfig
});
export function withAuth(HocComponent) {
return class extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false,
user: {},
renewIframe: false,
hasError: false,
errorMessage: null
};
}
async componentWillMount() {
msalAuth.handleRedirectCallback(() => {
let userAccount = msalAuth.getAccount();
this.setState({
isAuthenticated: true,
user: userAccount
});
}, (authErr, accountState) => { // on fail
console.log(authErr);
this.setState({
hasError: true,
errorMessage: authErr.errorMessage
});
});
if (msalAuth.isCallback(window.location.hash)) {
this.setState({
auth: {
renewIframe: true
}
});
return;
}
let userAccount = msalAuth.getAccount();
if (!userAccount) {
msalAuth.loginRedirect({});
return;
} else {
this.setState({
isAuthenticated: true,
user: userAccount
});
}
}
onSignIn() {
msalAuth.loginRedirect({});
}
onSignOut() {
msalAuth.logout();
}
render() {
if (this.state.renewIframe) {
return <div>hidden renew iframe - not visible</div>;
}
if (this.state.isAuthenticated) {
return <HocComponent auth={this.state} onSignIn={() => this.onSignIn()} onSignOut={() => this.onSignOut()} {...this.props} />;
}
if (this.state.hasError) {
return <div>{this.state.errorMessage}</div>;
}
return <div>Login in progress...</div>;
}
};
}
c. Update App.js
import { withAuth } from './msal/MsalAuthProvider';
import './custom.css'
class RootApp extends Component {
static displayName ="Azure AD application";
render () {
return (
<Layout>
...
</Layout>
);
}
}
//enable auth when we access the page
const App = withAuth(RootApp)
export default App;
call the API
import { msalAuth } from '../msal/MsalAuthProvider'
async componentDidMount() {
// get token and call the api
try {
const accessTokenRequest = {
scopes: ["api://872ebcec-c24a-4399-835a-201cdaf7d68b/access_as_user"]
}
var authRes
var accessToken = null;
try {
authRes = await msalAuth.acquireTokenSilent(accessTokenRequest);
accessToken=authRes.accessToken
}
catch (error) {
console.log("AquireTokenSilent failure");
authRes = await msalAuth.acquireTokenPopup(accessTokenRequest);
accessToken = authRes.accessToken
}
console.log(accessToken)
this.populateWeatherData(accessToken);
}
catch (err) {
var error = {};
if (typeof (err) === 'string') {
var errParts = err.split('|');
error = errParts.length > 1 ?
{ message: errParts[1], debug: errParts[0] } :
{ message: err };
} else {
error = {
message: err.message,
debug: JSON.stringify(err)
};
}
this.setState({
user: {},
isLoading: false,
error: error
});
}
}
async populateWeatherData(token) {
const response = await fetch('weatherforecast', {
method: 'get',
headers: new Headers({
'Authorization': 'Bearer ' + token
})
});
const data = await response.json();
this.setState({ forecasts: data, loading: false });
}
Server code
a. Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
services.AddControllersWithViews();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
b. Controller
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ITokenAcquisition tokenAcquisition;
public WeatherForecastController(ITokenAcquisition tokenAcquisition)
{
this.tokenAcquisition = tokenAcquisition;
}
[AuthorizeForScopes(Scopes = new[] { "<your scope>" })]
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
string accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(new[] { "<your scope>" });
......
......
}
}
For more details, please refer to here snd here.
Related
It's the first time I'm asking a question.
I want to build a graphQL server by using ASP.NET Core project.
I use this line by line, but in the end, it does not show the schema. I tried every thing that i could. The intresting is that the server works. the only thing is that does not show the schema.
here are some codes that I'm using.
Schema:
public class RootSchema : Schema, ISchema
{
public RootSchema(IDependencyResolver resolver) : base(resolver)
{
Query = resolver.Resolve<RootQuery>();
}
}
Query:
public class RootQuery : ObjectGraphType
{
public RootQuery()
{
Field<AuthorType>(
name: "authors", resolve: context =>
{
return new Author()
{
FirstName = "Jane"
};
});
}
}
The Controller:
[Route("graphql")]
public class GraphQLController : Controller
{
private readonly ISchema _schema;
private readonly IDocumentExecuter _executer;
private readonly IDependencyResolver _resolver;
public GraphQLController(ISchema schema, IDocumentExecuter executer, IDependencyResolver resolver)
{
_schema = schema;
_executer = executer;
_resolver = resolver;
}
[HttpGet(nameof(Test))]
public IActionResult Test()
{
return Ok("Salam");
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] GraphQLQuery query)
{
var result = await _executer.ExecuteAsync(_ =>
{
_.Schema = _schema;
_.Query = query.Query;
_.Inputs = query.Variables?.ToInputs();
}).ConfigureAwait(false);
if (result.Errors?.Count > 0)
{
return Problem(detail: result.Errors.Select(_ => _.Message).FirstOrDefault(), statusCode: 500);
}
return Ok(result.Data);
}
}
The Configure function at the sturtup:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseStaticFiles();
app.UseGraphiQl("/graphql");
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
The ConfigureServices function at the Sturtup:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IDependencyResolver>(_ => new
FuncDependencyResolver(_.GetRequiredService));
services.AddScoped<IDocumentExecuter, DocumentExecuter>();
services.AddScoped<IDocumentWriter, DocumentWriter>();
services.AddScoped<RootQuery>();
services.AddScoped<AuthorType>();
services.AddScoped<BlogPostType>();
services.AddScoped<ISchema, RootSchema>();
services.AddControllers();
services.AddControllersWithViews();
}
any help would be appreciated.
I have a very strange issue.
Suddenly, when I start debugging on my project, I am redirected to Home/Error instead of Home/Index
without any apparent error or message.
The application is very simple because I just created it today.
This is my startup:
public Startup(IConfiguration configuration)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault;
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(Configuration);
services.Configure<GzipCompressionProviderOptions>(options => options.Level = CompressionLevel.Optimal);
services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<GzipCompressionProvider>();
});
// Without AddNewtonsoftJson actions that receive JSON Objects Body will return error 406
services.AddControllersWithViews().AddNewtonsoftJson();
services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(60);
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddHttpContextAccessor();
services.AddTransient<IElasticsearchService, ElasticsearchService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
// Enable compression (must be before UseStaticFiles)
app.UseResponseCompression();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
And this is (the only one for now) my controller:
public HomeController(ILogger<HomeController> logger, IHttpContextAccessor httpContextAccessor, IElasticsearchService elasticsearchService)
: base (logger, httpContextAccessor, elasticsearchService) { }
public async Task<IActionResult> Index(Dictionary<string, string> #params)
{
// some code
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
string errorMessage = string.Empty;
if (TempData["ErrorMessage"] != null)
{
errorMessage = TempData["ErrorMessage"].ToString();
TempData["ErrorMessage"] = null;
}
ViewBag.ErrorMessage = errorMessage;
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
I think I solved the problem on my own, maybe the issue was, that I used a RedirectToPermanent() on my Index and from then on, it always redirect me on Error.
I cleaned the cache and the temporary files and now it seems to work.
We're working on an asp.net core project that depends on SignalR. Lastly we updated our project from ASP.NET Core 2.2 to 3.0 and SignalR stopped working. In the documentation we configured everything (I think correctly) but is still doesn't work. What did we miss?
ASP.NET Core 3.0 API
Startup:
public class Startup
{
private readonly string corsPolicy = "CorsPolicy";
private static string[] AllowdOrigins() => return new string[] {"localhost:4200","example.com"};
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
ConfigureAuthentication(services);
///MICROSOFT SQL DATABASE
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")
));
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
services.Configure<ForwardedHeadersOptions>(options =>
{
options.KnownProxies.Add(IPAddress.Parse("XX.XX.XX.XX"));
});
services.AddSignalR();
services.AddControllers();
//services dependencies
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(corsPolicy);
//app.UseForwardedHeaders(new ForwardedHeadersOptions
//{
// ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
//});
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<ChatHub>("/chat");
});
DummyData.Initialize(app);
}
private void ConfigureAuthentication(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(corsPolicy,
builder =>
{
builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowAnyOrigin()
.AllowCredentials()
.WithOrigins(AllowdOrigins());
});
});
services.AddHttpContextAccessor();
// configure strongly typed settings objects
var appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
// configure jwt authentication
var appSettings = appSettingsSection.Get<AppSettings>();
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
}
}
Chathub:
[EnableCors("CorsPolicy")]
public class ChatHub : Hub
{
private static Dictionary<string, int> onlineClientCounts = new Dictionary<string, int>();
private static readonly string FrontPrefix = "_FRONT";
public ChatHub()
{
}
[HubMethodName("ConnectFrontend")]
public async Task ConnectFrontend(int sessionId)
{
//////
}
[HubMethodName("ConnectDevice")]
public async Task ConnectDevice(int sessionId)
{
//// This method should be called but it isn't.
}
public void DisConnect(int sessionId, int userId)
{
//////////
}
[HubMethodName("SendJsonToFrontends")]
public async Task SendJsonToFrontends(int sessionId, string jsonString)
{
///
}
[HubMethodName("SendJsonToAll")]
public async Task SendJsonToAll(int sessionId, string jsonString)
{
////
}
}
Angular project
SignalRService:
export class SignalRService {
private connection: signalR.HubConnection;
public newMessage = new Subject<SocketMessage>();
constructor() {
}
public connectFront() {
this.connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:2525/chat")//(environment.baseSignalR)
.configureLogging(signalR.LogLevel.Trace)
.build();
this.connection.on("ReceiveJson", data => { this.handleJsonMessage(data) });
// handles the first connection message
this.connection.start().then(() => this.sendConnectionMessage());
// handles the incoming messages
this.connection.on("ReceiveJson", data => this.handleJsonMessage(data));
this.connection.on("ReceiveJsonFrontend", data => this.handleJsonMessage(data));
}
private sendConnectionMessage() {
var sessionId = sessionStorage.getItem("SessionId");
if (sessionId != null) {
this.connection.invoke("ConnectFrontend", sessionId).catch((error) => { debugger; console.log(error); });
}
}
public sendWebsocketMessageToAll(msg: SocketMessage) {
var sessionId = sessionStorage.getItem("SessionId");
if (sessionId != null) {
this.connection.invoke("SendJsonToAll", sessionId, JSON.stringify(msg)).catch((error) => console.log(error));
}
}
public sendWebsocketMessageToFrontend(msg: SocketMessage) {
var sessionId = sessionStorage.getItem("SessionId");
if (sessionId != null) {
this.connection.invoke("SendJsonToFrontends", sessionId, JSON.stringify(msg)).catch((error) => console.log(error));
}
}
private handleJsonMessage(data: string) {
this.newMessage.next(this.getSocketMessage(data));
}
public getSocketMessage(data: string): SocketMessage {
var msg: SocketMessage = JSON.parse(data);
return msg;
}
public disconnect() {
this.connection.stop();
}
}
angular output:
Api output:
Just create an web app API with angular template you can view my code for your ref
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.AddSignalR().AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.WriteIndented = false;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
endpoints.MapHub<ChatHub>("/chatHub");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
In FE side. Note: use new package #microsoft/signalr
import * as signalR from "#microsoft/signalr";
#Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
title = 'app';
ngOnInit() {
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.build();
connection.on("receiveMessage", (username: string, message: string) => {
console.log(username);
console.log(message);
});
connection.start().then(() => {
connection.send("sendMessage", "aaa", "aaaa")
.then(() => console.log("done"));
}).catch(err => document.write(err));
}
}
Well I finaly figured it out with the help of Tony,
Apperently It went wrong in the methods of the SignalR chat hub. The methods allowed only integers as parameters but it needed to be strings. I don't know it it has to do with some other settings but my guess now is that signalr cant convert the request parameters to something other then strings.
When I changed it to strings it worked.
It seems, that you have configured JWT based authentication on the server side and do not provide a token for SignalR connection. Try to provide a token using the accessTokenFactory:
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(`${environment.urlAddress}/chathub`, {
accessTokenFactory: () => this.token
})
.build()
I have created the web API for countries and try to access it from angular 7, the GET details and GET record by id is working fine where as DELETE method not working.
When i try to access DELETE there is no call send to web API from angular 7.
// DELETE: api/Country/5
[HttpDelete("{id}")]
public IActionResult Delete(long id) {
Country country = _dataRepository.Get(id);
if (country == null) {
return NotFound("The Employee record couldn't be found.");
}
_dataRepository.Delete(country);
return NoContent();
}
// GET: api/Countries
[HttpGet]
public IActionResult Get() {
IEnumerable < Country > country = _dataRepository.GetAll();
return Ok(country);
}
// GET: api/Country/5
[HttpGet("{id}", Name = "Get")]
public IActionResult Get(long id) {
Country country = _dataRepository.Get(id);
if (country == null) {
return NotFound("The Employee record couldn't be found.");
}
return Ok(country);
}
export class CountriesComponent {
public countries: Country[];
bUrl = 'https://localhost:44324/';
constructor(private http: HttpClient, private router: Router) {
this.http.get<Country[]>(this.bUrl + 'api/country').subscribe(result => {
this.countries = result;
}, error => console.error(error));
}
btnClick = function (id) {
this.router.navigateByUrl('/country-edit/' + id);
};
btnDelete = function (id) {
return this.http.delete(this.bUrl + 'api/Country/' + id);
// return this.http.get<Country[]>(this.bUrl + 'api/country/'+ id).subscribe(result => {
// this.countries = result;
// }, error => console.error(error));
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddDbContext<DataBaseContext>(opts => opts.UseSqlServer("server=.; database=FoodFactory; Integrated Security=SSPI"));
services.AddScoped<IDataRepository<Country>, CountryManager>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors(x => x.AllowAnyMethod());
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
Try check your web API webconfig, there might be missing verb DELETE.
Try to add the verb DELETE, example as below:
add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,DELETE" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
Hope this helps.
Updated (For .NET Core)
Step 1: Register CORS services
Call AddCors in Startup.ConfigureServices to add CORS services to the app's service container:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
Step 2: Enable CORS with CORS Middleware
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
}
Try if this works for you.
This application use Identity 4 with client mvc application and IDP(Identity provider) asp.net core web application.
Can't access Controller Index action view.
How to fix this Issue ????
IDP project Startup project (localhost:44393)
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddTestUsers(Config.GetUsers())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryClients(Config.GetClients());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseIdentityServer();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
//app.Run(async (context) =>
//{
// await context.Response.WriteAsync("Hello World!");
//});
}
}
Configure.cs file
public static class Config
{
public static List<TestUser> GetUsers()
{
return new List<TestUser>
{
new TestUser
{
SubjectId ="d866oef",
Username ="Kasunjith",
Password="password",
Claims= new List<Claim>
{
new Claim("given_name","Kasunjith"),
new Claim("family_name","Underwood"),
}
}, new TestUser
{
SubjectId ="d866omf",
Username ="BimalJith",
Password="password",
Claims= new List<Claim>
{
new Claim("given_name","BimalJith"),
new Claim("family_name","ViewWord"),
}
},
};
}
// identity-related resources (Scopes)
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>()
{
new Client
{
ClientName="Image Galary",
ClientId="imagegalleryclient",
AllowedGrantTypes = GrantTypes.Hybrid,
RedirectUris = new List<string>()
{
"https://localhost:44335/signin-oidc"
},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId
},
ClientSecrets =
{
new Secret("secret".Sha256())
}
}
};
}
}
Client application (localhost:44335)
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies",
(options) =>
{
}).AddOpenIdConnect("oidc", options => {
options.SignInScheme = "Cookies";
options.Authority = "https://localhost:44393";
options.ClientId = "imagegalleryclient";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.ClientSecret = "secret";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseAuthentication();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Gallery}/{action=Index}/{id?}");
});
}
}
My Controller class
[Authorize]
public class GalleryController : Controller
{
public async Task<IActionResult> Index()
{
await WriteOutIdentityInformation();
return View();
}
public async Task WriteOutIdentityInformation()
{
var identityToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.IdToken);
Debug.WriteLine($"Identity token:{identityToken}");
foreach (var claim in User.Claims)
{
Debug.WriteLine($"Claim type:{ claim.Type} -Claim value : {claim.Value}");
}
}
}
first after login using user name And Password
After go to localhost:44335/Gallary/index show this error
Not 100% sure on this, but I think by default AddOpenIdConnect will request OpenId and Profile scope, however, you've only granted your client OpenId scope, so need to add another one.
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
},