hzero微服务平台06: 代码分析之token生成、校验、获取信息、传递-ag真人官方网址

大家好!今天让小编来大家介绍下关于hzero微服务平台06: 代码分析之token生成、校验、获取信息、传递的问题,以下是酷知号的小编对此问题的归纳整理,让我们一起来看看吧。

目录概述从oauth服务获取token过程oauth服务校验token的过程如果快过期, 自动延长有效时间;服务间token的传递过程gateway获取用户信息(principal)的过程oauth服务创建用户信息(principal)的过程client_credentials模式password模式业务服务从jwt_token获取用户信息的过程

概述

功能介绍: 认证服务

oauth2是开放的标准协议, spring security oauth提供了实现, 授权中心(authorization server)用@enableauthorizationserver及相关配置实现, 资源服务(resource server)用@enableresourceserver及相关配置实现;
授权中心提供授权(/oauth/authorize)、获取token(/oauth/token)等接口, 资源服务实现对token的校验、信息提取; hzero的oauth服务即是授权中心也是资源服务;

资料:
oauth2.0的rfc文档: rfc 6749 - the oauth 2.0 authorization framework

spring官方开发文档: oauth 2 developers guide

调用过程阅读方法: 如何以纯文本方式简单快速记录java代码的调用过程

从oauth服务获取token过程

调试技巧: 在最内层的方法上打断点, 看调用堆栈;

post /oauth/token
tokenendpoint#postaccesstoken
oauth2accesstoken token = gettokengranter().grant(tokenrequest.getgranttype(), tokenrequest);  //责任链模式, 每种授权模式对应一个granter
abstracttokengranter#grant
clientdetails client = clientdetailsservice.loadclientbyclientid(clientid);
abstracttokengranter#getaccesstoken
return tokenservices.createaccesstoken(getoauth2authentication(client, tokenrequest));
    abstracttokengranter#getoauth2authentication //这个方法会被子类granter覆写
    return new oauth2authentication(storedoauth2request, null); 
defaulttokenservices#createaccesstoken(oauth2authentication)  //hzero修改版
defaulttokenservices#createaccesstoken(oauth2authentication , oauth2refreshtoken) //hzero修改版
return accesstokenenhancer != null ? accesstokenenhancer.enhance(token, authentication) : token;

"hzero修改版": hzero直接把spring的某些代码保留包名、类名复制到了项目里, 相当于直接替换了源码, 一种不太好的hack方法;
abstracttokengranter的子类authorizationcodetokengranter、implicittokengranter、clientcredentialstokengranter、resourceownerpasswordtokengranter分别对应四种授权模式, 可以增加新的granter, 优雅的实现新的认证方式.

oauth服务校验token的过程

oauth2authenticationprocessingfilter#dofilter
authentication authresult = authenticationmanager.authenticate(authentication);
oauth2authenticationmanager#authenticate
oauth2authentication auth = tokenservices.loadauthentication(token);
defaulttokenservices#loadauthentication
oauth2accesstoken accesstoken = tokenstore.readaccesstoken(accesstokenvalue);
customredistokenstore#readaccesstoken //从redis里读取、反序列化

如果快过期, 自动延长有效时间;

defaulttokenservices#loadauthentication

//如果快过期, 自动增加有效时间;
if (accesstoken.getexpiresin() < 3600) {
    long deltams = 4 * 3600 * 1000l; //4小时, 单位是毫秒;
    ((defaultoauth2accesstoken) accesstoken).setexpiration(new date(system.currenttimemillis()   deltams));
    tokenstore.storeaccesstoken(accesstoken, result);
}

服务间token的传递过程

前端使用oauth2流程获取token, 之后的请求必须携带token, token在传递示意图:

前端获取的uuid格式的token(相当于sessionid), 传递给网关;
网关使用uuid token获取用户信息, 把用户信息转换jwt token, 并添加到jwt_tokenheader里, 传递到后端服务; 如果获取用户信息失败, 直接返回401(认证失败);
后端服务从jwt_token里解析、获取用户信息;

gateway获取用户信息(principal)的过程

重点:

gateway把uuid转换为jwt是在addjwtfilter
用户信息最终是oauth服务从customredistokenstore里读取的;

gateway服务:
从gateway调用非public的任意接口时:

getuserdetailsfilter#run
customuserdetailswithresult result = this.getuserdetailsservice.getuserdetails(accesstoken);
getuserdetailsserviceimpl#getuserdetails //调用oauth服务的/oauth/api/user

注意: oauth/api/user接口是within接口, 直接从网关调用会报错: error.permission.withinforbidden

permission_with_inerror.permission.withinforbiddenno access to within interface

oauth服务:

// oauth/api/user
oauthcontroller#user
return principal;

principal来自securitycontext, securitycontext来自oauth2authenticationprocessingfilter:

oauth2authenticationprocessingfilter#dofilter
authentication authresult = authenticationmanager.authenticate(authentication);
    oauth2authenticationmanager#authenticate
    oauth2authentication auth = tokenservices.loadauthentication(token);
securitycontextholder.getcontext().setauthentication(authresult);

关于additioninfo字段:

defaulttokenservices#loadauthentication的返回结果包含additioninfo, 但序列化的之后不包含, 因为spring添加了ignore注解;
principal序列化把additioninfo字段里信息, 放到了和client_id同级的位置;

oauth服务创建用户信息(principal)的过程

principal来自object securitycontext.getauthentication().getprincipal(), object具体是什么类型需要看authenticationtoken设置了什么值;

client_credentials模式

principal是customclientdetails类型:

...
clientcredentialstokengranter#grant
abstracttokengranter#grant
clientdetails client = clientdetailsservice.loadclientbyclientid(clientid);
    customclientdetailsservice#loadclientbyclientid
    clientdetailswrapper.warp(clientdetails, client.getid(), client.getorganizationid());  //角色、租户等信息来自这里
return getaccesstoken(client, tokenrequest);
abstracttokengranter#getaccesstoken
return tokenservices.createaccesstoken(getoauth2authentication(client, tokenrequest));
clientcredentialstokengranter#getoauth2authentication //hzero修改版
return new clientoauth2authentication(storedoauth2request, new clientauthenticationtoken(client)); //new clientauthenticationtoken(client)的入参client是principal, 是customclientdetails

password模式

principal是customuserdetails类型:

...
resourceownerpasswordtokengranter#getoauth2authentication
userauth = authenticationmanager.authenticate(userauth);
    providermanager#authenticate
    abstractuserdetailsauthenticationprovider#authenticate
    user = retrieveuser(username,(usernamepasswordauthenticationtoken) authentication);
        customauthenticationprovider#retrieveuser
        return getuserdetailsservice().loaduserbyusername(username);
        customuserdetailsservice#loaduserbyusername
    return createsuccessauthentication(principaltoreturn, authentication, user);
return new oauth2authentication(storedoauth2request, userauth);

业务服务从jwt_token获取用户信息的过程

调试思路: 给jwttokenextractor打断点, 看调用堆栈;

业务服务里hzero没有用spring oauth的@enableresourceserver, 自定义了jwttokenfilter, 相当于oauth2authenticationprocessingfilter的功能:

jwttokenfilter#dofilter
authentication authentication = this.tokenextractor.extract(httprequest);
authentication authresult = this.authenticate(authentication);
    jwttokenfilter#authenticate
    this.tokenservices.loadauthentication(token); 
securitycontextholder.getcontext().setauthentication(authresult);

使用方法: 封装好的方法:
detailshelper.getuserdetails()

以上就是小编对于hzero微服务平台06: 代码分析之token生成、校验、获取信息、传递问题和相关问题的解答了,hzero微服务平台06: 代码分析之token生成、校验、获取信息、传递的问题希望对你有用!

© ag真人官方网址的版权声明
the end
喜欢就支持一下吧
分享