在Angular ASP.NET Core 2.0应用程序中使用LinkedIn API和Oauth 2.0进行身份验证

v1l68za4  于 2023-06-21  发布在  Angular
关注(0)|答案(2)|浏览(141)

我是Angular 5的新手,我正在ASP.NET Core 2.1应用程序中使用它。我试图通过外部服务使用其API来实现身份验证,但我被LinkedIn API卡住了。这与Google或Facebook的API完全不同,因为Linkedin改变了他的方法,用JSON取代了JS API。我使用的是Oauth 2.0 nuget包,提供Linkedin的Oauth。我有一个问题,与重定向到LinkedIn API与登录页面。我在没有Angular的情况下用ASP.NET Core应用程序测试了同样的方法,它工作正常,所以问题出在Angular方面,或者可能是我的项目没有正确配置为使用Angular。
我在点击LinkedIn按钮时添加了操作:

<button><img class="button-linkedIn" (click)="OnLinkedInLoad()" 
    src="../../assets/images/linkedIn-register2.png"></button>

它在login组件中处理:

@Component({
      moduleId: module.id,
      selector: 'app-login',
      templateUrl: './login.component.html',
      styleUrls: ['./login.component.css']
    })
    export class LoginComponent implements OnInit {

      ngOnInit() {
      }

      constructor(
        private userSrv: UsersService) { }

      OnLinkedInLoad() {
        this.userSrv.loginUserLinkedIn().subscribe()
      }
    }

登录组件使用users.service组件发送请求(GET):

@Injectable()
    export class UsersService {
      constructor(private httpClient: HttpClient) { }

      addUser(user: User) {
        return this.httpClient.post('/api/Users', user);
      }

      loginUserLinkedIn(): Observable<any> {
        return this.httpClient.get<any>('/api/Users/signInLinkedIn');
      }
    }

最后在UsersController中:

[Route("api/[controller]")]
    [ApiController]
    public class UsersController : ControllerBase
    {
        public UsersController(LoginTestContext context)
        {
        }

        [HttpGet("signInLinkedIn")]
        public async Task LinkedInSignInAsync()
        {
            await HttpContext.ChallengeAsync("linkedin", new AuthenticationProperties() { RedirectUri = "/" });
        }
    }

下面是我在启动时的配置:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<LoginTestContext>(options =>
                options.UseNpgsql(Configuration.GetConnectionString("LoginTestContext")));

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie(
                )
            .AddLinkedIn("linkedin", options =>
            {
                options.ClientId = this.Configuration.GetValue<string>("linkedin:clientid");
                options.ClientSecret = this.Configuration.GetValue<string>("linkedin:clientSecret");
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("Users/Error");                
            }

            //app.UseHsts();
            app.UseSpaStaticFiles();
            app.UseStaticFiles();
            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Users}/{action=Index}/{id?}");
            });

            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
        }
    }

编辑:
在调试过程中,我注意到控制台中的一个错误,单击LinkedIn按钮后,出现错误日志:

Access to XMLHttpRequest at
'https://www.linkedin.com/oauth/v2/authorization?client_id=XXXXXXXXX&scope=r_liteprofile%20r_emailaddress&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A44325%2Fsignin-linkedin&state=CfDJ8NjmD6pBjdpBuQvhUqQ7m6g41igeIumDrha6i0V2JZrOt1u6nweQ9cllyzBMFUj8F2dttqoYX7GYZs9wg-W4O2N8Y9XGPXUwkj5Ojl16sHlYHab93vT3jQEbSXuCQja-Fyths8Rw6YwId0-Ibg8sTeBK-IJSB6_VN16o7h9Nlw24M1Qo3ZRAR8Aq-Yp9DZSdLCVOfzz0yFkvkhy5cJ1OhC0'
(redirected from 'http://localhost:44325/api/Users/signInLinkedIn') from origin 'http://localhost:44325'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

我尝试了一些CORS策略的修复:
1)添加

services.AddCors();

配置到启动中的ConfigureServices方法,并

app.UseCors(builder => builder.AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin());

2)向HTTPContext响应添加标头:

this.ControllerContext.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");

3)调用loginUserLinkedIn时添加HttpHeaders

loginUserLinkedIn(): Observable<any> {
const headers = new HttpHeaders().append('Access-Control-Allow-Origin', ['*']);

return this.httpClient.get<any>('/api/Users/signInLinkedIn', { headers });

但是在这些修复之后,错误仍然发生。
如何在使用Angular的ASP.NET Core应用程序中正确设置CORS策略?

2skhul33

2skhul331#

MDN
跨域资源共享(CORS)是一种使用额外的HTTP头来告诉浏览器让在一个源(域)运行的Web应用程序有权访问来自不同源的服务器的选定资源的机制。
您尝试从localhost URL访问linkedin URL,这是一个 Cross-Origin 请求(从localhost到linkedin),您无法绕过此限制。
任何关于CORS的设置必须在LinkedIn网站上进行;- )
您希望通过c#代码通过 Authenticate Code flow(支持)验证用户身份,请参阅此Microsoft Linkedin doc
我不知道ChallengeAsync指令,但是,可能你必须将代码从

await HttpContext.ChallengeAsync("linkedin", new AuthenticationProperties() { RedirectUri = "/" });

Response.Redirect("https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id={your_client_id}&redirect_uri=https%3A%2F%2Fdev.example.com%2Fauth%2Flinkedin%2Fcallback&state=fooobar&scope=r_liteprofile%20r_emailaddress%20w_member_social');

否则,我认为挑战是由客户端应用程序(与CORS错误)。
要知道正确的URL,您可以:
1.阅读Microsoft Linkedin文档,您可以在其中看到一个示例
1.您可以尝试Fiddler嗅探ChallengeAsync调用的URL并粘贴到Response.Redirect命令

oyjwcjzk

oyjwcjzk2#

这段代码在我的@Component中为我解决了这个问题

onLinkedinLogin() {
      // this.socialAuthService.signInWithLinkedin();
      let linkedInCredentials = {
        clientId: "************",
        redirectUrl: "https://y8pud.codesandbox.io/linkedInLogin",
        scope: "r_liteprofile%20r_emailaddress%20w_member_social" // To read basic user profile data and email
      };
        window.location.href = `https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=*********&redirect_uri=${linkedInCredentials.redirectUrl}&scope=${linkedInCredentials.scope}`;
    }

您提供的代码允许用户从Angular应用程序发出请求而不会收到CORS错误,因为它从浏览器窗口本身执行请求,而不是从Angular应用程序的代码中执行请求。
在onLinkedinLogin函数中,应用程序将window.location.href设置为LinkedIn授权URL。这会导致浏览器导航到该URL,直接从浏览器发起请求。这种方法绕过了浏览器强制执行的同源策略,这是CORS的底层机制。
由于请求是由浏览器直接发起的,因此浏览器将处理任何必要的CORS头和与服务器的协商。这允许请求继续而不会遇到CORS错误。
为了在这种情况下处理跨域请求,需要在服务器端进行适当的CORS配置。

相关问题