美文网首页
基于Token的API接口认证机制

基于Token的API接口认证机制

作者: FX_SKY | 来源:发表于2017-06-07 19:16 被阅读1986次

Cookie Auth

Cookie认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie会被删除。但可以通过修改cookie 的expire time使cookie在一定时间内有效。

Token Auth的优点

Token机制相对于Cookie机制相比有以下优势:

  • 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输;
  • 无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息;
  • 更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.
    去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可;
  • 更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多;
  • CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。

认证过程

下面我们从一个实例来看如何运用JWT机制实现认证:

登录授权

  • 第一次登录,用户从浏览器输入用户名/密码,提交后台服务器的登录处理的Action层(Login Action);
  • Login Action调用认证服务进行用户名密码认证,如果认证通过,Login Action层调用用户信息服务获取用户信息(包括完整的用户信息及对应权限信息);
  • 验证用户信息合法后,Login Action从配置文件中获取Token签名生成的秘钥信息,进行Token的生成(可以调用第三方的JWT Lib生成签名后的JWT Token);
  • 完成JWT数据签名后,将其设置到COOKIE/HEADER 对象中,并重定向到首页,完成登录过程;

请求认证

基于Token的认证机制会在每一次请求中都带上完成签名的Token信息,这个Token信息可能在COOKIE
中,也可能在HTTP的Authorization头中。

过程如下:

  • 客户端(APP客户端或浏览器)通过GET或POST请求访问资源(页面或调用API);
  • 通过统一的Filter或者Interceptor 对请求进行拦截,首先在cookie中查找Token信息,如果没有找到,则在HTTP Authorization Head中查找;
  • 如果找到Token信息,则根据配置文件中的签名加密秘钥,调用JWT Lib对Token信息进行解密和解码;
  • 完成解码并验证签名通过后,对Token中的exp、nbf、aud等信息进行验证;
  • 全部通过后,根据获取的用户的角色权限信息,进行对请求的资源的权限逻辑判断;
  • 如果权限逻辑判断通过则通过Response对象返回;否则则返回HTTP 401;

基于JWT的Token认证机制实现

JWT

Java中对JWT的支持可以考虑使用JJWT开源库。
maven依赖:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>

JWT Token生成&验证代码:

import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.crypto.MacProvider;
import org.apache.commons.codec.Charsets;
import org.junit.Before;
import org.junit.Test;

import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;

/**
 * ${DESCRIPTION}
 *
 * @author Ricky Fung
 */
public class JwtTokenTest {

    private Key key;
    private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

    @Before
    public void init() {

        String secret = "ricky";
        //We will sign our JWT with our ApiKey secret
        byte[] apiKeySecretBytes = secret.getBytes(Charsets.UTF_8);
        key = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
    }

    @Test
    public void testEncode() {

        long ttl = 7200 * 1000;
        Date now = new Date();
        Date exp = new Date(now.getTime() + ttl);

        //Let's set the JWT Claims
        JwtBuilder builder = Jwts.builder().setId("ucode")
                .setIssuedAt(now)
                .setExpiration(exp)
                .setSubject("sub")
                .setIssuer("iss")
                .setAudience("aud")
                .setHeaderParam(Header.TYPE, Header.JWT_TYPE)
                .signWith(signatureAlgorithm, key);

        String compactJws = builder.compact();
        System.out.println(compactJws);
    }

    @Test
    public void testDecode() {
        String compactJws = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJ1Y29kZSIsImlhdCI6MTQ5NzIzOTE2NiwiZXhwIjoxNDk3MjQ2MzY2LCJzdWIiOiJzdWIiLCJpc3MiOiJpc3MiLCJhdWQiOiJhdWQifQ.gc0OcIlBQND8TlPN6q1nUQf852aIxK4mgkHBBrYMLZ4";

        try {
            Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(compactJws).getBody();

            //OK, we can trust this JWT
            System.out.println("ID: " + claims.getId());
            System.out.println("Subject: " + claims.getSubject());
            System.out.println("Issuer: " + claims.getIssuer());
            System.out.println("Audience: " + claims.getAudience());
            System.out.println("Expiration: " + claims.getExpiration());
        } catch (SignatureException e) {
            //don't trust the JWT!
        }
    }

    @Test
    public void testSimple() {

        Key key = MacProvider.generateKey();

        String compactJws = Jwts.builder()
                .setSubject("Joe")
                .signWith(SignatureAlgorithm.HS512, key)
                .compact();

        System.out.println(compactJws);
    }
}

相关文章

网友评论

      本文标题:基于Token的API接口认证机制

      本文链接:https://www.haomeiwen.com/subject/ufyafxtx.html