NutzCN Logo
分享 JWT身份验证 单点登录 分享
发布于 1800天前 作者 Hamming 2992 次浏览 复制 上一个帖子 下一个帖子
标签:

如果写某些接口 需要身份验证 jwt 简单 方便 那么就来分享一下
AOP 实现的身份验证
首先 maven引入关联jar

        <!-- api token web server -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.10.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.10.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.10.5</version>
            <scope>runtime</scope>
        </dependency>

创建jwt工具类

package io.nutz.nutzsite.common.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.nutz.mvc.Mvcs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Key;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * jwt验证工具类
 * @author Hamming_Yu on 2018/11/13.
 */
public class JWTUtil {
    private static Logger log = LoggerFactory.getLogger(JWTUtil.class);

    //We will sign our JWT with our ApiKey secret
    private static Key key;
    private static String issuer="nutzsite";

    static {
        //初始化api.key 文件存放位置
        Path fpath= Paths.get("api.key");
        //创建文件
        if(!Files.exists(fpath)) {
            try {
                Files.createFile(fpath);
//                Files.createDirectory(fpath);
                key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
                try ( ObjectOutputStream keyOut = new ObjectOutputStream(new FileOutputStream(fpath.toFile()))){
                    keyOut.writeObject(key);
                    keyOut.close();
                } catch (IOException e) {
                    log.debug(e.getMessage());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else {
            try (ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(fpath.toFile()))){
                key = (Key) keyIn.readObject();
                keyIn.close();
            } catch (IOException e) {
                log.debug(e.getMessage());
            } catch (ClassNotFoundException e) {
                log.debug(e.getMessage());
            }
        }
    }

    /**
     * 创建token
     * @param id
     * @return
     */
    public static String createJWT(String id) {
        //过期时间不要太长 移动端需要长时间记住用户名 让移动端本地存储 用户名 密码即可
        Date exp = DateUtils.addDays(new Date(),1) ;
        //Let's set the JWT Claims
        JwtBuilder builder = Jwts.builder().setId(id)
                .setIssuedAt(new Date())
                .setSubject(id)
                .setIssuer(issuer)
                .signWith(key);
        builder.setExpiration(exp);
        //Builds the JWT and serializes it to a compact, URL-safe string
        return builder.compact();
    }

    /**
     * 验证token
     * @param token
     * @return
     */
    public static boolean verifyToken(String token) {
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token).getBody();
            if(!issuer.equals(claims.getIssuer()) &&
                    !claims.getIssuer().equals( claims.getSubject() )  ){
                return false;
            }
            return true;
        } catch (Exception e) {
            log.debug(e.getMessage());
//            e.printStackTrace();
            return false;
        }
    }

    /**
     *  获取ID
     * @return
     */
    public static String getId() {
        HttpServletRequest request = Mvcs.getReq();
        Map<String, String> map = new HashMap<String, String>();
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        try{
            String token=map.get("authorization");
           if(verifyToken(token)){
               Claims claims = Jwts.parser()
                       .setSigningKey(key)
                       .parseClaimsJws(token).getBody();
               return  claims.getId();
           }
        }catch (Exception e){
            log.debug(e.getMessage());
            e.printStackTrace();

        }
        return null;
    }

    /**
     * Sample method to validate and read the JWT
     * @param jwt
     */
    public static void parseJWT(String jwt) {
        //This line will throw an exception if it is not a signed JWS (as expected)
        Claims claims = Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwt).getBody();
//        System.out.println("ID: " + claims.getId());
//        System.out.println("Subject: " + claims.getSubject());
//        System.out.println("Issuer: " + claims.getIssuer());
//        System.out.println("Expiration: " + claims.getExpiration());
    }
}

自定义注解

package io.nutz.nutzsite.common.annotation;

import java.lang.annotation.*;

/**
 * @Author: Haimming
 * @Date: 2019-05-17 16:52
 * @Version 1.0
 */
// 必须带这个,不然读取不到的
@Retention(RetentionPolicy.RUNTIME)
// aop,一般指方法
@Target({ElementType.METHOD})
// 记录到javadoc
@Documented
public @interface AccessToken {

}

AOP 实现

package io.nutz.nutzsite.common.aop;

import io.nutz.nutzsite.common.annotation.AccessToken;
import org.nutz.aop.MethodInterceptor;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.aop.SimpleAopMaker;
import org.nutz.ioc.loader.annotation.IocBean;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * @Author: Haimming
 * @Date: 2019-05-17 16:53
 * @Version 1.0
 */
@IocBean(name="$aop_access_token")
public class AccessTokenAopConfigration extends SimpleAopMaker<AccessToken> {

    @Override
    public List<? extends MethodInterceptor> makeIt(AccessToken accessToken, Method method, Ioc ioc) {
        return Arrays.asList(new AccessTokenAopInterceptor(ioc, accessToken, method));
    }

}

package io.nutz.nutzsite.common.aop;

import io.nutz.nutzsite.common.annotation.AccessToken;
import io.nutz.nutzsite.common.base.Result;
import io.nutz.nutzsite.common.utils.JWTUtil;
import org.nutz.aop.InterceptorChain;
import org.nutz.aop.MethodInterceptor;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.JsonFormat;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;

import java.lang.reflect.Method;

/**
 * @Author: Haimming
 * @Date: 2019-05-17 16:57
 * @Version 1.0
 */
@IocBean
public class AccessTokenAopInterceptor implements MethodInterceptor {
    private static final Log log = Logs.get();

    protected Ioc ioc;

    public AccessTokenAopInterceptor(Ioc ioc, AccessToken token, Method method) {
        this.ioc = ioc;
    }

    /**
     * 过滤器 验证登录
     * @param chain
     * @throws Throwable
     */
    @Override
    public void filter(InterceptorChain chain) throws Throwable {
        try {
            String token = Strings.sNull(Mvcs.getReq().getHeader("authorization"));
            if (JWTUtil.verifyToken(token)) {
                chain.doChain();
            }else {
                Mvcs.SKIP_COMMITTED =true;
                Mvcs.write(Mvcs.getResp(), Result.token(), JsonFormat.full());
            }
        } catch (Throwable e) {
            log.debug("aop.error", e);
            throw e;
        }
    }
}

package io.nutz.nutzsite.common.base;

import org.nutz.lang.Strings;
import org.nutz.mvc.Mvcs;

/**
 * 返回消息通用类
 * "result": 1,【4种状态,0:请求成功,1:请求失败,2: ,3:token失效】--类型为Integer
 * "msg": "相关内容解释",
 * "data": "数据主体"
 * @author wizzer
 * @date 2016/6/22
 */
public class Result {

    private int code;
    private String msg;
    private Object data;

    public Result() {
    }

    public Result(int code, String msg, Object data) {
        this.code = code;
        this.msg = Strings.isBlank(msg) ? "" : Mvcs.getMessage(Mvcs.getActionContext().getRequest(), msg);
        this.data = data;
    }

    public static Result success(String content) {
        return new Result(0, content, null);
    }

    public static Result success(String content, Object data) {
        return new Result(0, content, data);
    }

    public static Result error(int code, String content) {
        return new Result(code, content, null);
    }

    public static Result error(String content) {
        return new Result(1, content, null);
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return this.msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static Result token() {
        return new Result(3, "token失效", null);
    }
}

验证 是否有效 需要身份验证方法添加注解@AccessToken

    @GET
    @ApiOperation(value = "心跳接口", notes = "发我一个ping,回你一个pong", httpMethod="GET")
    @At
    @Ok("json:full")
    @AccessToken
    public Object ping() {
        return new NutMap("ok", true).setv("data", "pong");
    }

请求headers添加
authorization 即可正常访问

完整代码 请访问
https://github.com/HaimmingYu/NutzSite

0 回复
添加回复
请先登陆
回到顶部