美文网首页
基于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