SDU信息门户(3)图灵认证授权子系统:oauth协议详解

2021SC@SDUSC

目录

一.引言

1.OAUTH认证授权三个步骤

2.具体执行方式

二.Oauth模块部分代码分析

1.proto

2.domain\models

 三.总结


一.引言

1.OAUTH认证授权三个步骤

              1. 获取未授权的Request Token

              2. 获取用户授权的Request Token

              3. 用授权的Request Token换取Access Token

2.具体执行方式

A. 使用者(第三方软件)向OAUTH服务提供商请求未授权的Request Token。向Request Token URL发起请求。

B. OAUTH服务提供商同意使用者的请求,并向其颁发未经用户授权的oauth_token与对应的oauth_token_secret,并返回给使用者。

C. 使用者向OAUTH服务提供商请求用户授权的Request Token。向User Authorization URL发起请求,请求带上上步拿到的未授权的token与其密钥。

D. OAUTH服务提供商将引导用户授权。该过程可能会提示用户,你想将哪些受保护的资源授权给该应用。此步可能会返回授权的Request Token也可能不返回。如Yahoo OAUTH就不会返回任何信息给使用者。

E. Request Token 授权后,使用者将向Access Token URL发起请求,将上步授权的Request Token换取成Access Token。

F. OAUTH服务提供商同意使用者的请求,并向其颁发Access Token与对应的密钥,并返回给使用者。

G. 使用者以后就可以使用上步返回的Access Token访问用户授权的资源。

二.Oauth模块部分代码分析

1.proto

oauth:包括AuthorizationPayload 消息(包括userId和clientId),Authorization 消息中包括code授权码和AuthorizationPayload,SignTokenRes 包括 accessToken(访问令牌)refreshToken(刷新令牌)。

开放授权端服务OAuthService ,授权会话CreateAuthorization()输入令牌载体AuthorizationPayload,获取授权码AuthorizationCode;通过授权码获取会话信息,FindAuthorizationByCode (),返回的是Authorization;签发 accessToken 和 refreshToken
 通过给出AuthorizationCode授权码, 返回授权令牌和刷新令牌;刷新令牌 RefreshAccessToken 给出RefreshAccessTokenReq返回新的RefreshAccessTokenRes;获取令牌载体数据GetAccessTokenPayload () 给出AccessToken 返回 AuthorizationPayload。

syntax = "proto3";

package turing.connect.oauth.v1;

message AuthorizationPayload {
  string userId = 1;
  string clientId = 2;
  repeated string scopes = 3;
}

message Authorization {
  string code = 1;  // 授权码
  AuthorizationPayload payload = 2;
}

message AuthorizationCode {
  string code = 1;
}

message SignTokenRes {
  // 一天就过期呢
  string accessToken = 1;
  // 过期时间有点长喔
  string refreshToken = 2;
}

message RefreshAccessTokenReq {
  string refreshToken = 1;
}

message RefreshAccessTokenRes {
  string accessToken = 1;
  // 原样传回
  optional string refreshToken = 2;
}

message AccessToken {
  string accessToken = 1;
}

// 开放授权端服务
service OAuthService {
  // 创建授权会话,默认三分钟过期
  rpc CreateAuthorization(AuthorizationPayload) returns (AuthorizationCode);
  // 通过授权码获取会话信息
  // 授权码过期将抛出错误
  rpc FindAuthorizationByCode (AuthorizationCode) returns (Authorization);
  // 签发 accessToken 和 refreshToken
  rpc SignToken (AuthorizationCode) returns (SignTokenRes);
  // 刷新 accessToken
  rpc RefreshAccessToken (RefreshAccessTokenReq) returns (RefreshAccessTokenRes);
  // 获取令牌载体数据
  rpc GetAccessTokenPayload (AccessToken) returns (AuthorizationPayload);
}

user:包括UserData,SingInReq,SignInRes等message,SignIn方法传入参数类型SignInReq返回SignInRes,SignOut传入参数SignOutReq返回SignOutRes;FindById传入UserById返回UserData。

syntax = "proto3";

package turing.connect.user.v1;

message UserData {
  string casId = 1;
  string name = 3;
  enum UserRole {
    Student = 0;
    Teacher = 1;
  }
  UserRole role = 4;
  int32 grade = 5;
  string workplace = 6;
  string campus = 7;
  string major = 8;
  optional string type = 110;
}

message SignInReq {
  string casId = 1;
  string password = 2;
}

message SignInRes {}

message SignOutReq {
  string casId = 1;
}

message SignOutRes {}

message UserById {
  string casId = 1;
}

// 用户服务
service UserService {
  rpc SignIn(SignInReq) returns (SignInRes);
  rpc SignOut(SignOutReq) returns (SignOutRes);
  rpc FindById(UserById) returns (UserData);
}

2.domain\models

AuthorizationCode类,首先构造器传入_code,_createdAt,_expiresIn(有效时间)三个参数并配置了三个参数的get方法,还有一个getValid方法,首先将传入的createdAt参数调用它的getTime()方法得到授权码的创建时间,然后将创建时间加上传入的_expiresIn参数得到有效截止时间,最后先用Date.now()方法得到现在时间,将有效截止时间减去现在时间,大于0说明还未过期则返回true,小于零则说明过期则返回false。

export class AuthorizationCode {
  private _code: string;

  private _createdAt: Date;

  private _expiresIn: number;

  constructor(code: string, expiresIn: number, createdAt = new Date()) {
    this._code = code;
    this._expiresIn = expiresIn;
    this._createdAt = createdAt;
  }

  get code() {
    return this._code;
  }

  get createdAt() {
    return this._createdAt;
  }

  get expiresIn() {
    return this._expiresIn;
  }

  get valid() {
    const now = Date.now();
    const expiresAt = this._createdAt.getTime() + this._expiresIn;
    // 过期时间在现在之后则有效嘿嘿
    return expiresAt - now > 0;
  }

  toString() {
    return this._code;
  }
}

authorization-id类:构造类接受String类型code或者上面编写的AuthorizationCode类的对象,先进行类型判断,如果是String,直接进行 this._code = code,如果是AuthorizationCode,则提取code。

import { AuthorizationCode } from './authorization-code';

export class AuthorizationId {
  private _code: string;

  constructor(code: string | AuthorizationCode) {
    if (typeof code === 'string') {
      this._code = code;
    } else {
      this._code = code.code;
    }
  }

  toString() {
    return this._code;
  }
}

authorization-payload类:首先构造器得到userId,clientId, scopes: AuthorizationScope[]三个参数并赋值给私有变量,配置三个私有变量的get方法,其中AuthorizationScope类代码为enum AuthorizationScope {OpenId = 'openid',UserInfo = 'user-info'}。

import { AuthorizationScope } from './authorization-scope';

export class AuthorizationPayload {
  private _userId: string;
  private _clientId: string;
  private _scopes: AuthorizationScope[];

  constructor(userId: string, clientId: string, scopes: AuthorizationScope[]) {
    this._userId = userId;
    this._clientId = clientId;
    this._scopes = scopes;
  }

  get userId() {
    return this._userId;
  }

  get clientId() {
    return this._clientId;
  }

  get scopes() {
    return this._scopes;
  }
}

      先定义authorizatrepository接口,接口包括nextCode()方法得到授权码, idFromCode
  findById()得到授权Id,findById()根据Id得到授权,save()将传入的授权保存,然后用Symbol函数将Authorization Repository生成新的类型 AuthorizationRepositoryToken。

      解释一下Symbol:原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,Symbol值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。也就是说,由于Symbol值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。

  最后用AuthorizationRepositoryImplement 类向Inject装饰器注入来实现AuthorizationRepositoryToken接口。

import { Inject } from '@nestjs/common';
import { Authorization } from './authorization';
import { AuthorizationCode } from './authorization-code';
import { AuthorizationId } from './authorization-id';

export interface AuthorizationRepository {
  nextCode(): AuthorizationCode;
  idFromCode(code: AuthorizationCode): AuthorizationId;
  findById(id: AuthorizationId): Promise<Authorization | undefined>;
  save(authorization: Authorization): Promise<void>;
}

export const AuthorizationRepositoryToken = Symbol('Authorization Repository');

export const AuthorizationRepositoryImplement = () => Inject(AuthorizationRepositoryToken);

authorization类:首先构造器得到三个参数并赋值给私有变量_id, _code,_payload,配置三个私有变量的get方法。这个类的主要目的是为了之后的授权。关于导入的AggregateRoot :在存储库模式的上下文中,聚合根是客户机代码从存储库中加载的唯一对象,存储库封装对子对象的访问,从调用者的角度来看,它会自动加载子对象,要么在加载根的同时,要么在实际需要它们的时候(如延迟加载)。可能有一个 order 对象,它封装了多个 lineitem 对象上的操作。客户端代码不会直接加载 lineitem 对象,只会加载包含这些对象的顺序,这些顺序将是域的这一部分的聚合根。

import { AggregateRoot } from '@nestjs/cqrs';
import { AuthorizationCode } from './authorization-code';
import { AuthorizationId } from './authorization-id';
import { AuthorizationPayload } from './authorization-payload';

export class Authorization extends AggregateRoot {
  private _id: AuthorizationId;

  private _code: AuthorizationCode;

  private _payload: AuthorizationPayload;

  constructor(code: AuthorizationCode, payload: AuthorizationPayload) {
    super();
    this._id = new AuthorizationId(code.code);
    this._code = code;
    this._payload = payload;
  }

  get id() {
    return this._id;
  }

  get code() {
    return this._code;
  }

  get payload() {
    return this._payload;
  }
}

 三.总结

   本次学习 我了解在SDU信息门户教务系统的Oauth认证授权获取授权码,授权Id还有对应的对授权的有效时间的验证以便后续进行相应的三步授权。目前实现了输入令牌载体AuthorizationPayload,获取授权码AuthorizationCode;通过给出AuthorizationCode授权码, 返回授权令牌和刷新令牌;刷新令牌 RefreshAccessToken, 给出RefreshAccessTokenReq返回新的RefreshAccessTokenRes;获取令牌载体数据GetAccessTokenPayload () 给出AccessToken 返回 AuthorizationPayload。而三步授权的实现则通过下一节application类中的具体方法来实现。Oauth是图灵认证授权中最重要的模块。本模块使用的框架是nestjs框架,编程语言是TypeScript。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值