简体   繁体   English

ASP.Net Core 5 中的身份验证

[英]Authentication in ASP.Net Core 5

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:我在 VS 2019 中使用 React 模板创建了 asp.net 内核,我需要授权 controller 方法,所以我首先在 Z3A580F142203677F1F0BCAD30898F63F5 上注册了我的应用程序,然后开始使用此配置:

    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在 controller 我使用 AuthorizeForScopes 和 ITokenAcquisition 如下

    [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但是当我尝试获取数据时出现 CORS 错误

在此处输入图像描述

Can you help me你能帮助我吗

Regarding the issue, please refer to the following steps关于这个问题,请参考以下步骤

  1. Register client application and server application注册客户端应用程序和服务器应用程序

  2. Use React project template with ASP.NET Core使用带有 ASP.NET 核心的 React 项目模板

  3. Client application客户端应用

a.一个。 Install msal安装 msal

npm install msal

b.湾。 Define MsalAuthProvider .定义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. c。 Update App.js更新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;
  1. call the API致电 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 });
  }
  1. Server code服务器代码

a.一个。 Startup.cs启动.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 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 .有关详细信息,请参阅此处snd here

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM