技术文章

了解最新技术文章

当前位置:首页>技术文章>技术文章
全部 110 常见问题 0 技术文章 110

如何使用基于角色的 API 在 App Builder 中创建应用程序?

时间:2023-09-19   访问量:1027


首先,启动应用程序生成器并选择“创建新应用程序”。接下来,导航到“示例应用程序”部分并选择 HR 仪表板作为您项目的基础设计。从那里,您可以扩展和自定义设计以满足您的特定需求。

在低代码应用程序生成器中创建您的第一个应用程序

打开示例后,您会注意到已经为您创建了几个页面。但是,为了更好地满足我们项目的要求,您将需要对其中一些页面进行修改并创建新页面。

 在App Builder中进行修改

现在,让我们创建登录和注册页面。导航到“视图”选项卡并选择加号图标以创建一个新页面,我们将其命名为“注册页面”。

 在 App Builder 中创建登录和注册页面

为了保持一致性,我们也可以将主页面的背景重新用于注册页面。我们需要添加一个列布局。在此布局中,我们将包含一个带有注册内容的标题和五个输入字段以及一个按钮。值得注意的是,所有输入字段都应该是必填的,并且应该指定适当的类型。

使用 AppBuilder 创建注册页面

接下来,我们可以创建登录屏幕。此屏幕仅需要两个输入字段 - 一个用于电子邮件,一个用于密码。为了简化流程,我们可以复制注册页面并删除任何不必要的元素。

使用 AppBuilder 创建登录页面

创建两个页面后,我们可以在提交按钮下添加指向每个页面的链接。

在 App Builder 中添加每个页面的链接

主页将具有仪表板,它将显示当前用户在卡片组件中参加的所有事件。如果用户具有管理员角色,他们还将看到一个包含平台上所有事件的网格,允许他们根据需要执行 CRUD 操作。

使用 AppBuilder 创建仪表板页面

接下来,我们将创建一个用于添加新事件的页面。只有具有管理员角色的用户才能访问此页面,但我们将在本教程的后面部分介绍这一点。对于每个活动,我们都需要标题、类别、参加用户的电子邮件以及活动日期。

使用 AppBuilder 创建添加事件页面


此外,我们需要创建一个类似的页面来更改用户的角色与活动页面类似,此功能只有管理员才能访问。出于本演示的目的,我们仅支持授予其他用户管理员权限。

使用 AppBuilder 创建“将角色添加到用户”页面

创建所有页面后,我们可以将它们链接到侧边栏导航中。

使用 AppBuilder 在侧边栏组件中添加链接

无需手动连接API

幸运的是,手动连接我们的 API 是不必要的,因为我们可以通过 App Builder 将其作为数据源上传来直接完成此操作。首先,我们必须确保 API 正在运行,然后导航到“数据源”选项卡,选择加号图标,然后选择 REST API。从那里,我们有两个选择:

  1. 添加Swagger定义

  2. 或者使用 JSON URL

出于我们的目的,我们将利用Swagger 方法并添加 URL。

我们需要指定数据源的名称并继续下一步。然后,我们必须确定要包含哪些端点。对于此演示,我们将选择所有可用端点。但是,请务必注意,事件的所有端点都需要授权才能成功。因此,我们需要在 API 中从用户那里获取 JWT 令牌并将其添加到授权选项卡中。

在本教程的后面,我们将用当前用户的令牌替换它。设置授权后,我们可以继续选择数据,确保选择所有字段,然后单击完成。

将数据源上传到App Builder

数据源上传成功后,我们就可以在仪表板页面继续连接网格了首先,选择网格并从数据字段更新数据源。从那里,我们可以添加更新和删除操作,这些操作将链接到 API 中的端点,从而允许通过与网格交互来实时修改数据。

创建所有页面后,我们可以通过选择右上角的绿色按钮来预览应用程序。然后我们需要下载应用程序以方便进一步定制。

在 App Builder 中将数据源绑定到网格

本地运行创建的应用程序

下载应用程序后,解压缩项目并在 Visual Studio Code 中打开它。在终端中,运行“npm install”,然后运行“npm run start”以开始运行应用程序。

下一步是将登录和注册页面与我们的 API 连接起来。为此,我们必须添加调用 API 的函数。这些函数应添加到存储我们所有服务的 services/hrdashboard.service.ts 文件中。我们还必须添加两项功能,一项用于登录,一项用于注册。


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

……

公共 registerUser (数据:任何, contentType : string = 'application/json-patch+json, application/json, text/json, application/*+json' ) {

常量 选项 = {

标题 {

       '内容类型' 内容类型

}

} ;

常量 主体 = 数据

返回 这个。http post ( ` ${ API_ENDPOINT } /Auth/Register ` , body , options ) ;

}

公共 登录用户数据任何 内容类型字符串 = 'application / json-patch + json,application / json,text / json,application / * + json' {

常量 选项 = {

     标题 {

       '内容类型' 内容类型

     }

} ;

常量 主体 = 数据

返回 这个。http post ( ` ${ API_ENDPOINT } /Auth/Login ` , body , options ) ;

}

……

 


在下一步中,导航到 register-page.component.ts文件并添加输入属性的绑定。创建一个变量来存储错误消息,并在请求不成功时向用户显示验证信息。另外,添加一个在提交表单时触发的函数。此函数将检查是否所有字段都是必需的,如果是,则将 JWT 令牌存储在localStorage中并导航到主页。如果缺少任何字段,该函数应向用户显示错误消息。


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

22

23

导出 RegisterPageComponent {

电子邮件号码

名字字符串

姓氏字符串

密码字符串

确认密码字符串

错误消息字符串

构造函数

私人 hRAPIServiceHRAPIService

私有 路由器路由器

) { }

onSubmit 事件 {

event.preventDefault ( ) ;

if ( this.password ! == this.confirmedPassword ) { _

     这。errorMessage = '密码应该匹配!'

}

else if ( this.email && this.firstName && this.lastName && this.password ) { _ _ _ _

     这。hRAPI服务registerUser ({ 名字: this.firstName , 姓氏: this.lastName , 电子邮件: this.email , 密码: this.password , 确认密码: this.confirmedPassword })

     订阅({

       下一个:(响应 = > {

 


我们还需要更新register-page.component.html以绑定输入。


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

< div class = "列布局背景" > </ div >

< div class = "列布局组" >

   < h2= "h2" >

           登记

   </h2> _ _

   < p class = "error-message" > {{ errorMessage } } </p>

   < igx-input-group type = "border" class = "input" >

           <输入类型= "text"必需igxInput [( ngModel )] = "firstName" />

           <标签igxLabel >名字</标签>

   </ igx-输入组>

   < igx-input-group类型= "border"= "input_1" >

           <输入类型= "text"必需igxInput [( ngModel )] = "lastName" />

           <标签igxLabel >姓氏</标签>

   </ igx-输入组>

   < igx-input-group类型= "border"= "input_1" >

           <输入类型= "电子邮件"必需igxInput [( ngModel )] = "电子邮件" />

           <标签igxLabel >电子邮件</标签>

   </ igx-输入组>

   < igx-input-group类型= "border"= "input_1" >

           <输入类型= "密码"必需igxInput [( ngModel )] = "密码" />

           <标签igxLabel >密码</标签>

 


要设置errorMessage的样式,我们需要在 register-page.component.scss 中添加样式

 

全屏

1

2

3

4

5

6

.错误消息 {

文本对齐居中

保证金2雷姆 0

字体粗细粗体

颜色红色

}


与注册页面一样,我们需要创建属性来绑定输入和为登录页面提交表单时执行的函数。此函数将调用登录服务,通过发送电子邮件和密码来验证用户身份。如果身份验证成功,它将把jwt令牌存储在localStorage中并导航到主页。如果失败,它将向用户显示一条错误消息。我们还需要更新login-page.component.html以绑定输入。

登录.页面.组件.ts

全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

22

23

导出 LoginComponent {

电子邮件号码

名字字符串

姓氏字符串

密码字符串

确认密码字符串

错误消息字符串

构造函数

私人 hRAPIServiceHRAPIService

私有 路由器路由器

) { }

onSubmit 事件 {

event.preventDefault ( ) ;

if (这个.电子邮件 && 这个.密码) {

     这。hRAPI服务loginUser ({ 电子邮件: this.email , 密码: this.password })

       订阅({

         下一个:(响应 = > {

           本地存储setItem ( 'hr_app_token' , 响应[ '值' ]) ;

           这。路由器导航通过网址'/'

         } ,

 


登录页面.component.html


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

< div class = "列布局背景" > </ div >

<div class="column-layout group">

   <h2 class="h2">

           Login

   </h2>

   <p class="error-message">{{errorMessage}}</p>

   <igx-input-group type="border" class="input">

           <input type="text" igxInput [(ngModel)]="email"/>

           <label igxLabel>Email</label>

   </igx-input-group>

   <igx-input-group type="border" class="input_1">

           <input type="password" igxInput [(ngModel)]="password"/>

           <label igxLabel>Password</label>

   </igx-input-group>

     <按钮 点击= “onSubmit($event)” igxButton = “引发” igxRipple= “按钮” >

       登录

     </按钮>

</div> _ _

 


我们需要创建一个AuthService来帮助我们解码令牌,检查用户是否具有特定角色,并删除会话。为此,我们将创建一个名为auth.service.ts的新文件,我们应该将其导入到app.module.ts中。为了解码令牌,我们需要安装jwt-decode包。

全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

“@angular/core”导入{ 可注入 }

import jwt_decode from 'jwt-decode

';

type Token = {

Id?: string,

email?: string,

firstName?: string,

exp?: number,

role?: string,

sub?: string,

}

@Injectable({

providedIn: 'root'

})

export class AuthService {

decodeToken(token) {

       return jwt_decode(token);

}

getEmail() {

       const token = localStorage.getItem('hr_app_token');

       const {email}: Token = this.decodeToken(token);

为端点实施防护以提高安全性

为了增强安全性,我们需要为端点实施防护。我们将创建三个守卫,从anonymous-guard.ts开始此防护确保登录和注册页面仅可供未登录的用户访问。如果已登录的用户尝试访问这些页面,则应将其重定向到主页。

为了实现这个防护,我们将在应用程序目录中创建一个防护文件夹,并创建一个名为anonymous-guard.ts的新文件


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

22

23

import { Injectable } from '@angular/core';

import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from '@angular/router';

import { Observable } from 'rxjs';

import { AuthService } from '../services/auth.service';

@Injectable({

providedIn: 'root'

})

export class AnonymousGuard implements CanActivate {

constructor(private router: Router,

       private authService: AuthService) { }

canActivate(

       next: ActivatedRouteSnapshot,

       state: RouterStateSnapshot): Observable

<boolean | UrlTree>

| Promise

<boolean | UrlTree>

| boolean | UrlTree {

       if (!this.authService.isAuthenticated()) {

           return true;

       }

 


我们需要实现的下一个防护称为auth-guard该防护将确保某些页面只能由经过身份验证的用户访问。


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

22

23

import { Injectable } from '@angular/core';

import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from '@angular/router';

import { Observable } from 'rxjs';

import { AuthService } from '../services/auth.service';

@Injectable({

providedIn: 'root'

})

export class AuthGuard implements CanActivate {

constructor(private router: Router,

       private authService: AuthService) { }

canActivate(

       next: ActivatedRouteSnapshot,

       state: RouterStateSnapshot): Observable

<boolean | UrlTree>

| Promise

<boolean | UrlTree>

| boolean | UrlTree {

       if (this.authService.isAuthenticated()) {

           return true;

       }

       return this.router.parseUrl("/login-page");

 


第三个防护称为 admin-guard 将限制仅具有管理员角色的用户对某些页面的访问。


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

@Injectable({

providedIn: 'root'

})

export class AdminGuard implements CanActivate {

constructor(private router: Router,

       private authService: AuthService) { }

canActivate(

       next: ActivatedRouteSnapshot,

       state: RouterStateSnapshot): Observable

<boolean | UrlTree>

| Promise

<boolean | UrlTree>

| boolean | UrlTree {

       if (this.authService.isAdmin()) {

           return true;

       }

       return this.router.parseUrl("/login-page");

}

}

 


一旦我们创建了守卫,我们需要将它们应用到适当的路线。为此,请打开app-routing.module.ts并向每个路由添加一个canActivate属性以及相应的防护。

例如,登录和注册页面只能由尚未登录的用户访问,因此我们将AnonymousGuard添加到他们的路由中。母版页应该只能由经过身份验证的用户访问,因此我们将AuthGuard添加到该路由。最后,添加事件和添加角色页面只能由具有管理员角色的用户访问,因此我们将AdminGuard附加到这些路由。


全屏

1

2

3

4

5

6

7

8

9

10

export const routes: Routes = [

{ path: '', redirectTo: 'master-page', pathMatch: 'full' },

{ path: 'error', component: UncaughtErrorComponent },

{ path: 'master-page', loadChildren: () => import('./master-page/master-page.module').then(m => m.MasterPageModule), canActivate: [AuthGuard]},

{ path: 'register-page', component: RegisterPageComponent, data: { text: 'Register Page' }, canActivate: [AnonymousGuard]},

{ path: 'login-page', component: LoginPageComponent, data: { text: 'Login' }, canActivate: [AnonymousGuard]},

{ path: 'add-event', component: AddEventComponent, data: { text: 'Add Event' }, canActivate: [AdminGuard]},

{ path: 'add-role-to-user', component: AddRoleToUserComponent, data: { text: 'Add Role' }, canActivate: [AdminGuard]},

{ path: '**', component: PageNotFoundComponent } // must always be last

];


为了确保没有权限的用户无法访问导航中的某些链接,我们必须隐藏它们。为此,我们可以将*ngIf=”isUserAdmin()”指令添加到与 master-page.component.html 文件中的 ADD EVENT 和 ADD ROLE TO USER 选项相对应的igx-list-item元素中。通过这样做,我们确保这些链接仅对具有管理员权限的用户可见。

为了实现此功能,我们还需要更新master-page.component.ts文件。我们可以创建一个函数来检查当前用户是否是管理员,并在我们之前添加的*ngIf指令中使用它。

此外,我们需要创建一个注销函数并将其附加到与 LOGOUT 链接对应的igx-list-item的单击事件。这将允许用户在必要时注销系统。

它应该看起来像这样:


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

<span igxListThumbnail>

   < igx-avatar icon = "stars" [ roundShape ] = "true" class = "avatar_1" > </ igx-avatar >

</跨度>

<span igxListLine>

   <p class="ig-typography__subtitle-2 text_3">

             ADD EVENT

   </p>

</span>

</igx-list-item>

<igx-list-item [isHeader]="false" (click)="logout()">

<span igxListThumbnail>

   <igx-avatar icon="exit_to_app" [roundShape]="true" class="avatar_1"></igx-avatar>

</span>

<span igxListLine>

   <p class="ig-typography__subtitle-2 text_3">

             LOGOUT

   </p>

</span>

</igx-list-item>

 



全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

export class MasterPageComponent {

public listItemVisible = false;

constructor(private authService: AuthService,

private router: Router){}

isUserAdmin() {

return this.authService.isAdmin();

}

logout() {

this.authService.logout();

this.router.navigateByUrl('/login-page');

}

}

 


我们的下一步是在添加事件页面和 API 之间建立连接为此,我们需要在HRDashboard服务中创建一个新函数,该函数将处理用于创建新事件的HTTP POST请求。


全屏

1

2

3

4

5

6

7

8

9

10

public postEvent(data: any, contentType: string = 'application/json-patch+json, application/json, text/json, application/*+json'): Observable<any>{

const options = {

     headers: {

       'content-type': contentType,

       Authorization: `Bearer ${localStorage.getItem('hr_app_token')}`,

     },

};

const body = data;

return this.http.post(`${API_ENDPOINT}/Event`, body, options);

}

 


此外,在add-event.component.ts文件中,我们需要定义将输入字段绑定到组件的属性并添加onSubmit函数。由于电子邮件将在以逗号分隔的单个字段中接收,因此我们需要在将它们发送到 API 之前将其拆分


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

22

23

export class AddEventComponent {

emails: string;

category: string;

title: string;

date: string;

errorMessage: string;

constructor(private hrApiService: HRDashboardService,

private router: Router) {}

onSubmit(event) {

event.preventDefault();

const splitEmails = this.emails.split(', ');

if (this.emails && this.category && this.title && this.date) {

     this.hrApiService.postEvent({ category: this.category, title: this.title, date: this.date, userEmails: splitEmails})

       .subscribe({

         next: (response) => {

             this.router.navigateByUrl('/');

         },

         error: (error) => {

           console.log(error)

           this.errorMessage = error.error["errors"] ? Object.values(error.error["errors"])[0] as string : error.error;

 


更新仪表板

完成上述步骤后,我们可以继续更新仪表板。在此之前,我们必须修改HRDashboardService,以在具有授权标头的请求中将所有出现的“Bearer <auth-token>”替换为 Bearer ${localStorage.getItem('hr_app_token' )}。这确保我们使用正确的 JWT 令牌获取数据。

此外,我们需要向HRDashboardService添加一个新函数,该函数仅获取与当前用户相关的事件。

 

全屏

1

2

3

4

5

6

7

8

public getMyEvents(): Observable<any>{

const options = {

     headers: {

       Authorization: `Bearer ${localStorage.getItem('hr_app_token')}`,

     },

};

return this.http.get(`${API_ENDPOINT}/Event`, options);

}


在仪表板页面上显示用户事件

接下来,我们将使用卡片组件在仪表板页面上显示用户的事件。为此,我们需要打开dashboard.component.html 文件并使用*ngFor指令基于myEvents属性呈现igx-card组件,该属性将包含当前用户的事件。此外,我们可以使用*ngIf=”isUserAdmin()”来确保网格仅对管理员可见。此外,我们应该更新仪表板上的问候语以显示当前用户的电子邮件,例如“早上好,{{email}}!”。

生成的文件应如下所示:


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

22

23

<div class="row-layout group">

<div class="column-layout group_1">

       <div class="column-layout group_2">

           <div class="row-layout group_3">

               <div class="column-layout group_4">

                   <h5 class="h5">

                         Good Morning, {{email}}!

                   </h5>

                   <p class="text">

                          Your Highlights

                   </p>

               </div>

           </div>

           <div class="row-layout group_5">

               <igx-card *ngFor="let event of myEvents; index as i;"type="outlined" class="card">

                   <igx-card-media height="200px">

                                   <img src="/assets/Illustration1.svg" class="image" />

                   </igx-card-media>

                   <igx-card-header>

                       <h3 igxCardHeaderTitle>

                                {{event.title}}

 


dashboard.component.ts文件中,我们需要定义两个属性:myEventsemail这些属性应使用ngOnInit函数中的相关数据填充


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

export class DashboardComponent implements OnInit {

public hRDashboardEventAll: any = null;

myEvents: any;

email: any;

constructor(

private hRDashboardService: HRDashboardService,

private authService: AuthService,

) {}

ngOnInit() {

this.hRDashboardService.getEventAll().subscribe(data => this.hRDashboardEventAll = data);

this.hRDashboardService.getMyEvents().subscribe(data => this.myEvents = data);

this.email = this.authService.getEmail();

}

public isUserAdmin() {

return this.authService.isAdmin();

}

 


现在,我们可以在仪表板上看到当前用户的所有事件,如果用户是管理员,他们可以从网格中更新和删除条目。

将添加角色连接到用户页面和 API

最后一步是在添加角色到用户页面和API之间建立连接为此,我们需要在HRDashboard服务中创建一个函数,用于从API获取用户数据并填充电子邮件选择组件。


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

public getUsers(): Observable

<any>

{

const options = {

     headers: {

       Authorization: `Bearer ${localStorage.getItem('hr_app_token')}`,

     },

};

return this.http.get(`${API_ENDPOINT}/User`, options);

}

public changeUserRole(data: any): Observable

<any>

{

const options = {

     headers: {

       Authorization: `Bearer ${localStorage.getItem('hr_app_token')}`,

     },

};

const body = data;

return this.http.post(`${API_ENDPOINT}/User/Role`, body, options);

 


完成后,我们可以转到add-role-to-user.component.ts并获取它们。我们还应该创建onSubmit函数,该函数将从HRDashboard服务调用changeUserRole最终结果应如下所示:


全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

export class AddRoleToUserComponent {

users: any;

email: string;

role: string;

constructor(private hrApiService: HRDashboardService,

private router: Router) { }

ngOnInit() {

this.hrApiService.getUsers()

     .subscribe(data => {

       this.users = data;

     });

}

onSubmit(event) {

event.preventDefault();

if (this.email && this.role) {

     this.hrApiService.changeUserRole({ email: this.email, role: this.role})

       .subscribe({

         next: (response) => {

             this.router.navigateByUrl('/');

         },

 



全屏

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17 号

18

19

20

21

<div class="row-layout group">

   <div class="column-layout group_1">

       <h2 class="h2">

                 Add Role to user

       </h2>

       <div class="row-layout group_2">

                 <igx-select type="border" class="select"[(ngModel)]="email">

           <igx-select-item *ngFor="let user of users; index as i;" value="{{user.email}}">

                         {{user.email}}

           </igx-select-item>

                   <label igxLabel>Email</label>

                 </igx-select>

                 <igx-select type="border" class="select"[(ngModel)]="role">

           <igx-select-item value="Administrator">

                         Administrator

           </igx-select-item>

                   <label igxLabel>Role</label>

                 </igx-select>

       </div>

           <按钮igxButton = "raised" ( click ) = "onSubmit($event)" igxRipple class = "button" >

             提交

 


遵循必要的步骤并完成所需的任务后,我们现在拥有一个功能齐全的应用程序,该应用程序已使用 App Builder 构建并与 API 集成。这意味着我们的应用程序现在能够与 API 进行通信,使用户能够执行各种操作,例如创建新事件、向用户添加角色以及查看其个性化仪表板。 


上一篇:5 个必备的 Angular Grid 基于列的功能

下一篇:使用 Figma 自动布局和 App Builder 加速设计到代码

发表评论:

评论记录:

未查询到任何数据!

在线咨询

点击这里给我发消息 售前咨询专员

点击这里给我发消息 售后服务专员

在线咨询

免费通话

24小时免费咨询

请输入您的联系电话,座机请加区号

免费通话

微信扫一扫

微信联系
返回顶部