基于Token的身份验证,用户登录

最近在看项目中的用原生JS封装的api请求方法,各种回调看到头晕,其中对于token,jwt一直是一知半解,有必要记录一下百度的知识。文章最后贴上项目封装请求后端的api代码,大家可以交流一下

Token 的中文有人翻译成 “令牌”,我觉得挺好,意思就是,你拿着这个令牌,才能过一些关卡。

基于 Token 的身份验证方法

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

 

JWT

实施 Token 验证的方法挺多的,还有一些标准方法,比如 JWT,读作:jot ,表示:JSON Web Tokens 。JWT 标准的 Token 有三个部分:

  • header
  • payload
  • signature

中间用点分隔开,并且都会使用 Base64 编码,所以真正的 Token 看起来像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

非常抽象吧,来分解一下。

Header

header 部分主要是两部分内容,一个是 Token 的类型,另一个是使用的算法,比如下面类型就是 JWT,使用的算法是 HS256。

{
  "typ": "JWT",
  "alg": "HS256"
}

Payload

Payload 里面是 Token 的具体内容,这些内容里面有一些是标准字段,你也可以添加其它需要的内容。下面是标准字段:

  • iss:Issuer,发行者
  • sub:Subject,主题
  • aud:Audience,观众
  • exp:Expiration time,过期时间
  • nbf:Not before
  • iat:Issued at,发行时间
  • jti:JWT ID

比如下面这个 Payload ,用到了 iss 发行人,还有 exp 过期时间。另外还有两个自定义的字段,一个是 name ,还有一个是 admin 。

{
 "iss": "ninghao.net",
 "exp": "1438955445",
 "name": "wanghao",
 "admin": true
}

 Signature

JWT 的最后一部分是 Signature ,这部分内容有三个部分,先是用 Base64 编码的 header.payload ,再用加密算法加密一下,加密的时候要放进去一个 Secret ,这个相当于是一个密码,这个密码秘密地存储在服务端。

  • header
  • payload
  • secret
var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload); 
HMACSHA256(encodedString, 'secret');

 

最后这个在服务端生成并且要发送给客户端的 Token 看起来像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

客户端收到这个 Token 以后把它存储下来(localstorage),下回向服务端发送请求的时候就带着这个 Token 。服务端收到这个 Token ,然后进行验证,通过以后就会返回给客户端想要的资源。

 

Authorization是什么?

headers.append("Authorization", "Bearer " + jwt);

下面再解释一下认证(authentication)和授权(authorization) 的区别。

举个例子来说: 
你要登机,你需要出示你的身份证和机票,身份证是为了证明你张三确实是你张三,这就是 authentication;而机票是为了证明你张三确实买了票可以上飞机,这就是 authorization。 

在 computer science 领域再举个例子: 
你要登陆论坛,输入用户名张三,密码1234,密码正确,证明你张三确实是张三,这就是 authentication;再一check用户张三是个版主,所以有权限加精删别人帖,这就是 authorization。

new Header()中很多方法都还一知半解,有必要逐一击破

 

下边第二个链接有关于token处理方法的封装,包括解释项目中

 

参考:

基于 Token 的身份验证

用HttpPost登陆验证时,用户名和密码放在请求头部header中的处理方法,形式为Authorization: username password。

 

项目api原生封装源码

import { Injectable } from "@angular/core";
import { Http, Headers, RequestOptions } from "@angular/http";
import { Router } from "@angular/router";
import "rxjs/add/operator/catch";
import "rxjs/add/operator/map";
import { AppConfig } from "app/app.config";

/**
 * 通用API服务,用于简单的调用后端的Controller及其方法,避免后端人员自行处理Restful类型API的麻烦
 */
@Injectable()
export class API {
  public _url: string;
  /**
     * 设置API地址,如果是多个服务器,请使用Nginx或者其它网关软件先行统一地址
     * @param url API地址
     */
  set url(url: string) {
    this._url = url;
  }

  get url(): string {
    if (!this._url) {
      return (this._url = window["baseUrl"] + "/api.do");
    }
    return this._url;
  }

  /**
     * 注入http服务
     * @param http
     */
  constructor(public http: Http, public router: Router) {}

  /**
     * IPS服务调用
     */
  ips(): any {
    let newInstance = _.clone(this);
    newInstance.url = window["ipsBaseUrl"]
      ? window["ipsBaseUrl"] + "/api.do"
      : AppConfig.ipsBaseUrl + "/api.do";
    return newInstance;
  }

  public call(...args: any[]): any {
    if (args.length < 1) {
      throw new Error("At least one argument for $rpc call ");
    }
    let name = args[0];
    args = args.slice(1);
    // 定义Http头
    let headers = new Headers({
      "Content-Type": "application/json"
    });
    // 从localStorage中获取登录令牌
    let jwt = localStorage["jwt"];
    if (jwt) {
      headers.append("Authorization", "Bearer " + jwt);
    } else {
      headers.append("Authorization", "Bearer anonymous.anonymous");
    }
    // 设置http头
    let options = new RequestOptions({ headers: headers });
    // 优化名字参数,提高鲁棒性
    name = name.substring(0, 1).toLowerCase() + name.substring(1);
    let request = {
      name: name,
      token: localStorage.getItem("request-token"),
      args: args
    };
    // 请求服务器
    let response = this.http
      .post(this.url, request, options)
      .map(res => res.json())
      .catch(error => error && error.json());
    // 定义处理器
    let handlers = {};
    // 订阅返回结果并处理
    response.subscribe(
      json => {
        let ok = handlers["ok"];
        let fail = handlers["fail"];
        if (json["error"] || json["cause"]) {
          //登录失效,自动跳转登录页面
          if (json["code"] === -9999) {
            // this.router.navigateByUrl("security/login");
            this.router.navigateByUrl("security");

            return;
          }
          /*tslint:disable*/
          console.error(name + ":" + json["cause"]);
          /*tslint:enable*/
          if (fail instanceof Function) {
            fail(json);
          }
        } else {
          if (ok instanceof Function) {
            ok(json);
          }
        }
      },
      error => {
        let fail = handlers["fail"];
        if (fail instanceof Function) {
          fail(error);
        }
      }
    );
    // 拟态返回器
    let result = {
      ok: fn => {
        handlers["ok"] = fn;
        return result;
      },
      fail: fn => {
        handlers["fail"] = fn;
        return result;
      }
    };
    return result;
  }
}

 

转载于:https://my.oschina.net/u/2949632/blog/1523130

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值