zoukankan      html  css  js  c++  java
  • 使用angular4和asp.net core 2 web api做个练习项目(三)

    第一部分: http://www.cnblogs.com/cgzl/p/7755801.html

    第二部分: http://www.cnblogs.com/cgzl/p/7763397.html

    后台代码: https://github.com/solenovex/asp.net-core-2.0-web-api-boilerplate

    前台代码: https://github.com/solenovex/angular-4-client-panel-app

    下面将开发登陆和授权的部分, 这里要用到identity server 4.

    在VS解决方案中设置多个项目同时启动:

    AspNetIdentityAuthorizationServer就是authorization server. 它的地址是 http://localhost:5000

    CoreApi.Web作为api, 都已经配置好了.它的地址是 http://localhost:5001

    Login 登陆

    由于我们使用的是Identity Server 4的登录页面, 所以angular项目里面无需登录页面, 把login相关的文件删除...........

    登陆需要使用到oidc-client.js所以通过npm安装:

    npm install --save oidc-client

    Auth Service

    需要登陆服务 auth.service:

    ng g s services/auth

    打开auth.services.ts:

    import { Injectable, OnInit, EventEmitter } from '@angular/core';
    import { Observable } from 'rxjs/Observable';
    import { User, UserManager, Log } from 'oidc-client';
    import 'rxjs/add/observable/fromPromise';
    
    const config: any = {
      authority: 'http://localhost:5000',
      client_id: 'corejs',
      redirect_uri: 'http://localhost:4200/login-callback',
      response_type: 'id_token token',
      scope: 'openid profile coreapi',
      post_logout_redirect_uri: 'http://localhost:4200/index.html',
    };
    Log.logger = console;
    Log.level = Log.DEBUG;
    
    @Injectable()
    export class AuthService implements OnInit {
    
      private manager: UserManager = new UserManager(config);
      public loginStatusChanged: EventEmitter<User>;
    
      constructor() {
        this.loginStatusChanged = new EventEmitter();
      }
    
      ngOnInit() {
    
      }
    
      login() {
        this.manager.signinRedirect();
      }
    
      loginCallBack() {
        return Observable.create(observer => {
          Observable.fromPromise(this.manager.signinRedirectCallback())
            .subscribe(() => {
              this.tryGetUser().subscribe((user: User) => {
                this.loginStatusChanged.emit(user);
                observer.next(user);
                observer.complete();
              }, e => {
                observer.error(e);
              });
            });
        });
      }
    
      checkUser() {
        this.tryGetUser().subscribe((user: User) => {
          this.loginStatusChanged.emit(user);
        }, e => {
          this.loginStatusChanged.emit(null);
        });
      }
    
      private tryGetUser() {
        return Observable.fromPromise(this.manager.getUser());
      }
    
      logout() {
        this.manager.signoutRedirect();
      }
    }

    config是针对identity server 4服务器的配置, authorization server的地址是 http://localhost:5000, 登陆成功后跳转后来的地址是: http://localhost:4200/login-callback

    其中的UserManager就是oidc-client里面的东西, 它负责处理登录登出和获取当前登录用户等操作.

    这里login()方法被调用后会直接跳转到 authorization server的登录页面.

    登录成功后会跳转到一个callback页面, 里面需要调用一个callback方法, 这就是loginCallback()方法.

    loginStatusChanged是一个EventEmitter, 任何订阅了这个事件的component, 都会在登录用户变化时(登录/退出)触发component里面自定义的事件.

    logout()是退出, 调用方法后也会跳转到authorization server的页面.

    最后别忘了在app.module里面注册:

      providers: [
        ClientService,
        AuthService
      ],

    登陆成功后跳转回掉页面 

    建立一个跳转回掉的component和路由:

    ng g c components/loginCallback

    修改app.module的路由:

    const appRoutes: Routes = [
      { path: '', component: DashboardComponent },
      { path: 'login-callback', component: LoginCallbackComponent },
      { path: 'register', component: RegisterComponent },
      { path: 'add-client', component: AddClientComponent },
      { path: 'client/:id', component: ClientDetailsComponent },
      { path: 'edit-client/:id', component: EditClientComponent }
    ];

    打开login-callback.component.ts:

    import { Component, OnInit } from '@angular/core';
    import { AuthService } from '../../services/auth.service';
    import { Router } from '@angular/router';
    import { User } from 'oidc-client';
    
    @Component({
      selector: 'app-login-callback',
      templateUrl: './login-callback.component.html',
      styleUrls: ['./login-callback.component.css']
    })
    export class LoginCallbackComponent implements OnInit {
    
      constructor(
        private authService: AuthService,
        private router: Router
      ) { }
    
      ngOnInit() {
        this.authService.loginCallBack().subscribe(
          (user: User) => {
            console.log('login callback user:', user);
            if (user) {
              this.router.navigate(['/']);
            }
          }
        );
      }
    
    }

    这里主要是调用oidc的回掉函数. 然后跳转到主页.

    html:

    <p>
      登录成功!
    </p>

    这个html, 基本是看不见的.

    修改Navbar

    navbar.component.html:

    <nav class="navbar navbar-expand-md navbar-light bg-light">
      <div class="container">
        <a class="navbar-brand" href="#">Client Panel</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault"
          aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
    
        <div class="collapse navbar-collapse" id="navbarsExampleDefault">
          <ul class="navbar-nav mr-auto">
            <li *ngIf="isLoggedIn" class="nav-item">
              <a class="nav-link" href="#" routerLink="/">Dashboard </a>
            </li>
          </ul>
          <ul class="navbar-nav ml-auto">
            <li *ngIf="!isLoggedIn" class="nav-item">
              <a class="nav-link" href="#" routerLink="/register">Register </a>
            </li>
            <li *ngIf="!isLoggedIn" class="nav-item">
              <a class="nav-link" href="#" (click)="login()">Login </a>
            </li>
            <li *ngIf="isLoggedIn" class="nav-item">
              <a class="nav-link" href="#" (click)="logout()">Logout </a>
            </li>
          </ul>
        </div>
      </div>
    </nav>
    <br>

    主要是检查是否有用户登陆了, 有的话不显示注册和登陆链接, 并且显示退出链接按钮. 没有的话, 则显示注册和登录.

    navbar.component.ts:

    import { Component, OnInit } from '@angular/core';
    import { Router } from '@angular/router';
    import { AuthService } from '../../services/auth.service';
    import 'rxjs/add/operator/map';
    import { User } from 'oidc-client';
    import { FlashMessagesService } from 'angular2-flash-messages';
    
    @Component({
      selector: 'app-navbar',
      templateUrl: './navbar.component.html',
      styleUrls: ['./navbar.component.css']
    })
    export class NavbarComponent implements OnInit {
    
      public isLoggedIn: boolean;
      public loggedInUser: User;
    
      constructor(
        private authService: AuthService,
        private router: Router,
        private flashMessagesService: FlashMessagesService
      ) { }
    
      ngOnInit() {
        this.authService.loginStatusChanged.subscribe((user: User) => {
          this.loggedInUser = user;
          this.isLoggedIn = !!user;
          if (user) {
            this.flashMessagesService.show('登陆成功', { cssClass: 'alert alert-success', timeout: 4000 });
          }
        });
        this.authService.checkUser();
      }
    
      login() {
        this.authService.login();
      }
    
      logout() {
        this.authService.logout();
      }
    
    }

    在ngOnInit里面订阅authservice的那个登录状态变化的事件. 以便切换导航栏的按钮显示情况.

    angular的部分先到这, 然后要

    修改一个identity server的配置:

    在VS2017打开AspNetIdentityAuthorizationServer这个项目的Config.cs文件, 看GetClients()那部分, 里面有一个Client是js client, 我们就用这个....

    // JavaScript Client
                    new Client
                    {
                        ClientId = CoreApiSettings.Client.ClientId,
                        ClientName = CoreApiSettings.Client.ClientName,
                        AllowedGrantTypes = GrantTypes.Implicit,
                        AllowAccessTokensViaBrowser = true,
    
                        RedirectUris =           { CoreApiSettings.Client.RedirectUris },
                        PostLogoutRedirectUris = { CoreApiSettings.Client.PostLogoutRedirectUris },
                        AllowedCorsOrigins =     { CoreApiSettings.Client.AllowedCorsOrigins },
    
                        AllowedScopes =
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile,
                            CoreApiSettings.CoreApiResource.Name
                        }
                    }

    打开CoreApiSettings, 它在SharedSettings这个项目里面:

    namespace SharedSettings.Settings
    {
        public class CoreApiSettings
        {
            #region CoreApi
    
            public static string AuthorizationServerBase = "http://localhost:5000";
            public static string CorsPolicyName = "default";
            public static string CorsOrigin = "http://localhost:4200";
            public static (string Name, string DisplayName) CoreApiResource = ("coreapi", "Core APIs");
            public static (string ClientId, string ClientName, string RedirectUris, string PostLogoutRedirectUris, string AllowedCorsOrigins) Client =
                ("corejs", "Core Javascript Client", "http://localhost:4200/login-callback", "http://localhost:4200/index.html", "http://localhost:4200");
    
            #endregion
        }
    }

    把相应的地址改成和angular auth.service里面config一样的地址才能工作.

    这里面使用了C# 7的命名Tuple, 非常好用.

    差不多可以了, 运行VS. 同时运行angular项目:

    1. 首次浏览:

    2. 点击登陆:

    点击登陆就跳转到authorization server的登录页面了, 你在这里需要注册一个用户.....

    然后输入用户名密码登陆.

    3.同意授权

    点击yes 同意授权.

    4.跳转回angular页面:

    首先跳转回的是angular的login-callback路由, 然后瞬间回到了主页:

    5. 刷新, 还是可以取得到登录的用户.

    但是如果再打开一个浏览器实例就无法取得到登陆用户了, oidc应该是把登陆信息存到了session storage里面.

    打开浏览器F12--Application:

    可以看到在session storage里面确实有东西, 而 localstorage里面却没有.

    今天比较忙, 先写到这... 估计还得写一篇....

  • 相关阅读:
    转载(SQL Server 存储过程的分页)
    学会了怎么样利用捕获异常提示数据库主键重复错误
    遇到.net加了验证控件的表单无法提交的问题
    过劳死IT界杀手 [注:该文属于转载,非原创],好可怕啊!
    很喜欢的一些道理。
    学会了在DropDownList的项里加多个空格
    好东东:asp.net利用多线程执行长时间的任务,客户端显示出任务的执行进度的示例
    javascript判断字符长度最好的方法
    layui中使用layverify进行非必填整数校验
    SuppressWarnings抑制警告的关键字
  • 原文地址:https://www.cnblogs.com/cgzl/p/7768147.html
Copyright © 2011-2022 走看看