iOS开发 - 基于Token的身份验证-JWT

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS开发 - 基于Token的身份验证-JWT相关的知识,希望对你有一定的参考价值。

参考技术A JWT就是一个字符串,经过加密处理与校验处理的字符串,形式为: A.B.C

header格式为

它就是一个json串,两个字段是必须的,不能多也不能少。alg字段指定了生成C的算法,默认值是HS256
将header用Base64Url编码,得到A
通常,JWT库中,可以把A部分固定写死,用户最多指定一个alg的取值

将上面的JSON对象进行Base64Url编码,得到B

将A.B使用RS256加密(其实是用header中指定的算法),当然加密过程中还需要密钥(自行指定的一个字符串)。
加密得到C,学名signature,其实就是一个字符串。作用类似于CRC校验,保证加密没有问题。
现在A.B.C就是生成的token了。

可以使用
JWT调试

Objective-C JWT https://github.com/yourkarma/JWT

我们使用的是RSA256
文档

生成环境是在mac系统下,使用openssl进行生成,首先打开终端,按下面这些步骤依次来做:打开openssl

1.生成模长为1024bit的私钥文件 private_key.pem

注意:这一步会提示输入国家、省份、mail等信息,可以根据实际情况填写,我测试了不填写的情况,会报错.这里会提示输入密码

注意:这一步会提示给私钥文件设置密码,直接输入想要设置密码即可,然后敲回车,然后再验证刚才设置的密码,再次输入密码,然后敲回车,完毕!
在解密时,private_key.p12文件需要和这里设置的密码配合使用,因此需要牢记此密码.

把.der和.p12格式的秘钥文件导入工程中,把私钥和秘钥发给后台,使用一套私钥秘钥,就完成了JWT token的生成!

使用JWT 进行基于 Token 的身份验证方法

一般weby应用服务都使用有状态的session来存储用户状态以便认证有权限的用户进行的操作。但服务器在做横向扩展时,这种有状态的session解决方案就受到了限制。所以在一些通常的大型web应用场景越来越多在采用没有状态的token来进行用户签权处理。

需要把Web应用做成无状态的,即服务器端无状态,就是说服务器端不会存储像会话这种东西,而是每次请求时access_token进行资源访问。这里我们将使用 JWT 1,基于散列的消息认证码,使用一个密钥和一个消息作为输入,生成它们的消息摘要。该密钥只有服务端知道。访问时使用该消息摘要进行传播,服务端然后对该消息摘要进行验证。

认证步骤
1.客户端第一次使用用户名密码访问认证服务器,服务器验证用户名和密码,认证成功,使用用户密钥生成JWT并返回
2.之后每次请求客户端带上JWT
3.服务器对JWT进行验证

首先使用JWTUtil类 来完成生成token和验证token的工作

public class JwtUtil {
    private static String SECRET = "com.mozi.shop.secret";
    private static String ISSUER = "MoziShop";

    /**
     * 生成token
     *
     * @param claims
     * @return
     */
    public static String createToken(Map<String, String> claims) throws Exception {

        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTCreator.Builder builder = JWT.create()
                    .withIssuer(ISSUER)
                    //设置过期时间为2小时
                    .withExpiresAt(DateUtils.addHours(new Date(), 2));
            claims.forEach(builder::withClaim);
            return builder.sign(algorithm);
        } catch (Exception e) {
            throw new Exception("生成token失败");
        }
    }

    /**
     * 验证jwt,并返回数据
     */
    public static Map<String, String> verifyToken(String token) throws Exception {
        Algorithm algorithm;
        Map<String, Claim> map;
        try {

            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
               JWTVerifier verifier = JWT.require(algorithm).build();
               DecodedJWT jwt = verifier.verify(token);
               return true;*/
            ///
            algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build();
            //JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            map = jwt.getClaims();
        } catch (Exception e) {
            throw new Exception("鉴权失败");
        }
        Map<String, String> resultMap = new HashMap<>(map.size());
        map.forEach((k, v) -> resultMap.put(k, v.asString()));
        return resultMap;
       }
    }

在用户进行正常登录操作时返回客户端一个和失效时间的token
/**
 * 登录页面
 */
public void index(){
    String username = getPara("username");
    String password = getPara("password");
   // System.out.println("LOGIN USERNAME:"+username);
    if(StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)){
        Member member = new Member().dao().findByUsername(username);
        if(member == null){
            //setAttr("feedback", Feedback.error("用户不存在"));
            setAttr("feedback", "用户不存在");
            //System.out.println("LOGIN USERNAME 用户不存在:"+username);
            render("/templates/"+getTheme()+"/"+getDevice()+"/login.html");
            return;
        }else if(!DigestUtils.md5Hex(password).equals(member.getPassword())){
            //setAttr("feedback", Feedback.error("用户名密码错误"));
            setAttr("feedback", "用户名密码错误");
            render("/templates/"+getTheme()+"/"+getDevice()+"/login.html");
            return;
        }else{
            /////jwt start///////////////////////////////////////////

            Map<String, String> map = new HashMap<>();
            map.put("id", (member.getId()).toString());
            map.put("name", member.getUsername());
            map.put("openid", member.getWeixinOpenId());
            String token = null;
            try {
                token = JwtUtil.createToken(map);
            }catch (Exception e) {

            }

            this.getResponse().setHeader("token", token);

            /////jwt end////////////////////////////////////////////
            redirect("/");
            return;
        }
    }else{
        System.out.println("nousername and pwd!!!!!!!!!!!!!!!");
        render("/templates/"+getTheme()+"/"+getDevice()+"/login.html");
    }
}
然后在需要授权的访问中鉴定用户携带的token,验证有效就进行操作
        String token =  getRequest().getHeader("token");
        try {
            Map<String, String> res = JwtUtil.verifyToken(token);
            System.out.println(JSON.toJSONString(res));
        }catch (Exception e) {
            System.out.println(e);
        }

以上是关于iOS开发 - 基于Token的身份验证-JWT的主要内容,如果未能解决你的问题,请参考以下文章

基于Token的身份验证——JWT

基于Token的身份验证——JWT(转)

WebApi_基于Token的身份验证——JWT(z)

使用JWT 进行基于 Token 的身份验证方法

基于jwt的token验证

这种基于 JWT 的身份验证方法安全吗?