基于JWT的token认证架构机制---拦截器验证token

一.架构:
客户应用从授权服务器获取Access Token,
授权服务器将Access Token和Jwt放到Redis服务器,过期时间很短
客户应用携带这Access Token去访问Api网关,
Api网关请求redis服务器对用户AccessToken进行对比,并拿到Jwt
Api网关携带着Jwt和微服务进行交互,微服务从JWT中获取用户信息(有的没有这步,直接传入用户信息的no等)
二.概念:
JWT 介绍:
含义:J–json W—Web T----token
结构:头部.载荷.签名
代码:用HS256 对称算法加密 用RS256 非对称算法加密
比如
header的json对象— {“typ”:“JWT”,“alg”:“HS256”}
payload的json对象–{“sub”:“1234567890”,“name”:“John Doe”,“admin”:true}
signature–将第一第二加密后的加盐secret加密,secret类似于私钥保存在服务端
三.java实战
我们使用jjwt来简化jwt的使用
3.1:导入依赖

io.jsonwebtoken
jjwt
0.6.0

对于key和过期时间保存在yml里
jwt:
config:
key: itcast
ttl: 360000
取得方式有两种
第一种@Value("${jwt.config.key}")
private String key
第二种:拿一个类来接配置
@ConfigurationProperties(“jwt.config”)
@Data
@Component
public class JwtUtil {
private String key ;
private long ttl ;//一个小时
}
注入之后使用

    **3.2创建生成token类**
long  exp=now+1000*60;过期时间为1分钟

                    **JwtBuilder builder= Jwts.builder().setId(admin.getId(0)
                                                   .setSubject(admin.getName())
                                                   .setIssuedAt(new Date())  //签发时间
                                                   .signWith(SignatureAlgorithm.HS256,"itcast");//设置签名密钥
                                                   .setExpiration(new Date(exp))  //设置过期时间(可以没有)
                                                   //自定义携带信息
                                                   .claim("roles","admin")
                                                   .claim("logo","logo.png")
                                                    System.out.println( builder.compact() );** 


    **3.3验证token** 

Claims claims =Jwts.parser()
.setSigningKey(“itcast”)
.parseClaimsJws(token)
.getBody();
System.out.println(“id:”+claims.getId());
System.out.println(“logo:”+claims.get(“logo”));
System.out.println(“subject:”+claims.getSubject());
SimpleDateFormat sdf=new SimpleDateFormat(“yyyy‐MM‐dd hh:mm:ss”);
System.out.println(“签发时间:”+sdf.format(claims.getIssuedAt()));
System.out.println(“过期时间:”+sdf.format(claims.getExpiration()));
System.out.println(“当前时间:”+sdf.format(new Date()) );

如果签名不对,运行时就会报错的,过期的时候会报io.jsonwebtoken.ExpiredJwtException异常

附带::从请求头里拿到token
头信息Authorization ,内容为Bearer+空格+token
@Autowired
private HttpServletRequest request;

String authHeader = request.getHeader(“Authorization”);/
if(!authHeader.startsWith("Bearer ")){
return new Result(false,StatusCode.ACCESSERROR,“权限不足”);
}
String token=authHeader.substring(7);//提取tok

使用拦截器来token鉴权

HandlerInterceptorAdapter这个适配器,继承后为我们提供三个方法
:预处理,后处理,返回处理
在preHandle中,可以进行编码、安全控制等处理;
在postHandle中,有机会修改ModelAndView;
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。

第一步:创建jwtFilter拦截器类,继承HandlerInterceptorAdapter适配器
@Component
public class JwtFilter extends HandlerInterceptorAdapter {
@Autowired
private JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
System.out.println(“经过了拦截器”);
final String authHeader = request.getHeader(“Authorization”);
if (authHeader != null && authHeader.startsWith(“Bearer “)) {
final String token = authHeader.substring(7);
Claims claims = jwtUtil.parseJWT(token);
if (claims != null) {
if(“admin”.equals(claims.get(“roles”))){//如果是管理员
request.setAttribute(“admin_claims”, claims);
}
if(“user”.equals(claims.get(“roles”))){//如果是用户
request.setAttribute(“user_claims”, claims);
}
}
}
return true;
}
}
第二步.配置拦截器类
@Configuration
public class ApplicationConfig extends WebMvcConfigurationSupport {
@Autowired
private JwtFilter jwtFilter;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtFilter).
addPathPatterns(”/").
excludePathPatterns("/
/login”);
}
}
第四步:在control层可以拿到request里存的信息

Claims claims=(Claims) request.getAttribute(“admin_claims”);
if(claims==null){
return new Result(true,StatusCode.ACCESSRROR,“无权访问”);
}

第二种:RS256非对称加密 非对称加密—需要私钥和公钥,用公钥来请求
第一步:
/**
* 创建加密key
*/
public static RSAKey getKey() throws JOSEException {
RSAKeyGenerator rsaKeyGenerator = new RSAKeyGenerator(2048);
RSAKey rsaJWK = rsaKeyGenerator.generate();
return rsaJWK;
}
第二步用map和key生成token
JWSSigner signer = new RSASSASigner(rsaJWK);

    JWSObject jwsObject = new JWSObject(
            new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(rsaJWK.getKeyID()).build(),
            new Payload(new JSONObject(payloadMap))
    );
    //进行加密
    jwsObject.sign(signer);

    String token= jwsObject.serialize();
    return token;

第三步:解析token

//验证token
public static Map validRS256(String token,RSAKey rsaJWK) throws ParseException, JOSEException {
//获取到公钥
RSAKey rsaKey = rsaJWK.toPublicJWK();
JWSObject jwsObject = JWSObject.parse(token);
JWSVerifier jwsVerifier = new RSASSAVerifier(rsaKey);
//验证数据
return verify(jwsObject, jwsVerifier);
}

你可能感兴趣的:(基于JWT的token认证架构机制---拦截器验证token)