【问题标题】:Obtaining Profile Photo from MS Graph API to Angular app从 MS Graph API 获取个人资料照片到 Angular 应用程序
【发布时间】:2021-09-30 20:08:12
【问题描述】:

我是 Angular 新手,我正在尝试从我的 Angular 应用程序调用 Microsoft Graph API 以显示来自 Microsoft 帐户的个人资料照片。身份验证过程使用 Azure AD 执行。

环境.ts

 azure: {
    tenantId: "xxxxxxxxxxxxxxxxxxxxxx", 
    applicationId: "xxxxxxxxxxxxxxxxxxx", 
    endpoint: {
      root: 'https://graph.microsoft.com/v1.0',
      profile: '/me',
      profilePhoto: '/me/photo'
    },
    redirectUri: 'http://localhost:4200'
  }

我开发了一个代码来验证从 API 获取个人资料照片。下面是我的

profile.component.ts

get_profile_photo() {
    this.msg.getProfilePhoto().subscribe(
      (response) => {
        console.log('get_profile_photo() success');
        console.log(response);
        this.profilePhoto = response;
      },
      (error) => {
        console.error("Error getting MS Graph Profile \n" + JSON.stringify(error));
        throw (error);
      }
    )
  }

这将调用

ms-graph.service.ts

getProfilePhoto() {
    return this.httpClient.get<ProfilePhoto>(
        env.azure.endpoint.root+'/me/photo'
    );
}

然后我得到如下成功响应

{@odata.context: "https://graph.microsoft.com/v1.0/$metadata#users('…a69c7-94ad-49ad-8d5d-xxxxxxxxxxxx')/photo/$entity", @odata.mediaContentType: "图片/jpeg", @odata.mediaEtag: "W/"94777476813e1400e64bca040592df3b92f1ec7c2baxxxxxxxxxxxxxxx"", id: "648x648", height: 648, ...}

但这需要在将 URL 传递给 src="" 属性之前转换为 base64。 我参考了网上的许多教程,但无法转换。

然后我尝试了以下方法,使用上述身份验证从 MS 帐户获取个人资料照片。

ms-graph.service.ts

getImage(imageUrl: string): Observable<File> {
    return this.http
      .get(imageUrl, {responseType: 'blob'})
      .map((res: Response) => res.blob);
  }

第二个选项我的 ts 代码是这样的

profile.component.ts

 createImageFromBlob(image: Blob) {
    let reader = new FileReader();
    reader.addEventListener("load", () => {
      this.imageToShow = reader.result;
      console.log(this.imageToShow);
      return this.imageToShow;
    }, false);
    if (image) {
      reader.readAsDataURL(image);
    }
  }
  get_profile_photo() {
    this.isImageLoading = true;
    this.imageService.getImage('https://graph.microsoft.com/v1.0/me/photo').subscribe(data => {
      this.createImageFromBlob(data);
      this.isImageLoading = false;
    }, error => {
      this.isImageLoading = false;
      console.log(error);
    })
  }

然后我得到了以下错误。

core.js:6479 ERROR TypeError: Cannot read property 'get' of undefined
    at ImageService.getImage (image.service.ts:12)
    at ProfileComponent.get_profile_photo (profile.component.ts:65)
    at ProfileComponent_Template_button_click_23_listener (profile.component.html:15)
    at executeListenerWithErrorHandling (core.js:15308)
    at wrapListenerIn_markDirtyAndPreventDefault (core.js:15346)
    at HTMLButtonElement.<anonymous> (platform-browser.js:560)
    at ZoneDelegate.invokeTask (zone.js:406)
    at Object.onInvokeTask (core.js:28659)
    at ZoneDelegate.invokeTask (zone.js:405)
    at Zone.runTask (zone.js:178)

谁能帮我解决这个问题并从 MS 帐户获取个人资料照片?

【问题讨论】:

    标签: angular azure api


    【解决方案1】:

    我遇到了同样的问题,并且工作正常。所以,在这里分享一下我的经验。它可以帮助他人。

    根据官方doc,没有端到端的例子。

    这是我的

    profile.service.ts

    import { Injectable, OnInit } from '@angular/core';
    import {
      HttpClient,
      HttpErrorResponse,
      HttpHeaders,
      HttpResponse,
    } from '@angular/common/http';
    import { Observable, throwError } from 'rxjs';
    import { catchError, map, tap } from 'rxjs/operators';
    
    @Injectable()
    export class ProfileService implements OnInit {
    
      constructor(private http: HttpClient) {}
    
      ngOnInit() {
    
      }
    
      getImage(imageUrl: string): Observable<Blob> {
        return this.http
          .get(imageUrl, {
            responseType: 'blob',
            headers: new HttpHeaders({ 'Content-Type': 'image/jpeg' }),
          })
          .pipe(
            map((res: any) => {
              return res;
            })
          );
      }
    }
    

    profile.component.ts

    import { Component, OnInit, Injector, OnDestroy, Inject } from '@angular/core';
    import { UserProfileService } from './user-profile.service';
    import { DomSanitizer } from '@angular/platform-browser';
    
    const GRAPH_ENDPOINT_GET_PHOTO =
      'https://graph.microsoft.com/v1.0/me/photo/$value';
    
    @Component({
      selector: 'app-profile',
      styleUrls: ['./profile.component.scss'],
      templateUrl: './profile.component.html',
      providers: [ProfileService],
    })
    export class ProfileComponent implements OnInit
    {
    
      isImageLoading: boolean = false;
      imageToShow: any;
    
      constructor(
        private _profileService: ProfileService,
        private domSanitizer: DomSanitizer
      ) {
      }
    
      ngOnInit() {
         // To get user's photo
         this.getProfilePicture();();
      }
    
      getProfilePicture() {
        this.isImageLoading = true;
        this._profileService.getImage(GRAPH_ENDPOINT_GET_PHOTO).subscribe(
          (blob) => {
            this.isImageLoading = false;
    
            var urlCreator = window.URL || window.webkitURL;
            this.imageToShow = this.domSanitizer.bypassSecurityTrustUrl(
              urlCreator.createObjectURL(blob)
            );
          },
          (error) => {
            this.isImageLoading = false;
            console.log(error);
          }
        );
      }
    
      createImageFromBlob(image: Blob) {
        let reader = new FileReader();
        reader.addEventListener(
          'load',
          () => {
            console.log(reader.result);
            const imgRes: any = reader.result;
            this.imageToShow = this.domSanitizer.bypassSecurityTrustUrl(imgRes);
          },
          false
        );
        if (image) {
          reader.readAsDataURL(image);
        }
      }
    
    }
    

    最后

    profile.component.html

    <div class="container">
    <img
      [src]="imageToShow"
      alt="Place image title" onerror="this.onerror=null;this.src='./assets/images/user_placeholder_img.jpg';"
      *ngIf="!isImageLoading; else noImageFound"
    />
    <ng-template #noImageFound>
      <img
        src="./assets/images/user_placeholder_img.jpg"
        alt="Fallbackimage"
      />
    </ng-template>
    </div>
    

    注意:这里我通过 MSALInterceptorConfigFactory 使用 Authorization Bearer 令牌。

    【讨论】:

    • 我有两个问题。 1) 为什么在您的 profileService 中有代码 ngOnInit。 2)方法createImageFromBlob(image: Blob) ,没看懂怎么用。谢谢
    【解决方案2】:

    要以二进制格式获取个人资料照片数据,端点 URL 应为 https://graph.microsoft.com/v1.0/me/photo/$valuehttps://graph.microsoft.com/v1.0/me/photo 返回关于头像的元数据,而不是内容。

    我对 Angular 不熟悉,但这是我在某个时候写的代码,用于获取个人资料照片内容。请注意,此代码是纯 JavaScript。

    axios.get('https://graph.microsoft.com/v1.0/me/photo/$value', {
        headers: {
            'Authorization': `Bearer ${accessToken}`
        },
        responseType: 'blob'
    })
    .then((response) => {
        const url = window.URL || window.webkitURL;
        const blobUrl = window.URL.createObjectURL(response.data);
        //You can use this blobUrl as src value in img tag.
    }
    

    【讨论】:

    • 通过执行此代码,我得到一个错误“属性 'then' 在类型 'Observable 上不存在”。原因是什么?另外,这里的“axios”是什么?另一件事是,虽然我们可以通过服务访问,但从组件访问 URL 并不是一个好习惯。
    • 就像我在回答中所说的那样,我对 Angular 不熟悉,所以我在我的应用程序中编写了这段 JS 代码。您需要将此代码转换为 Angular。 axios 是发出 HTTP 请求的库。
    猜你喜欢
    • 1970-01-01
    • 2014-06-24
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-19
    相关资源
    最近更新 更多