梳理一下流程
1.调用方需要获取到token(由code和secret和随机数加密生成)
2.调用接口前先通过服务端的要求传入相应的数据生成token,调用接口时把token传入
3.由服务端接收到token进行验证
4.验证成功后对url进行鉴权
接口信息以及权限信息回放在数据库中(mysql以及redis)
资源信息表
调用方身份表;java后端、app端、H5…要进行区分
中间表;每种身份所对应的资源
HTTP请求返回的数据统一放入ResponseModel类中.省略了get set方法
public class ResponseModel<T> {
/**
* 通配符
**/
private static final String WILDCARD_ALL = "*";
/**
* 响应状态码
**/
private volatile String code = HttpCode.BAD_REQUEST.getCode();
/**
* 响应状态码对应的提示信息
**/
private volatile String message = HttpCode.BAD_REQUEST.getMessage();
/**
* 响应内容
**/
private volatile T content = null;
public ResponseModel() {
}
}
把code和secret放入配置文件中;要与数据库中的一致
@Value("${microservices.code}")
private String microservicesCode;
@Value("${microservices.secret}")
private String microservicesSecret;
在调用接口、执行http请求之前先获取token,把code和secret传入
这边先不管接口的鉴权流程,先看token的获取流程然后再说鉴权流程
/**
* http请求公共方法
* @param url
* @param params
* @param method get and post
* @return
*/
protected ResponseModel HttpCommon(String url ,Map params,String method){
ResponseModel responseModel=null;
//获取token
String uToken = partnerService.getToken(microservicesCode, microservicesSecret);
//调用微服务接口传入token进行鉴权并返回结果;params为查询条件map
if("post".equalsIgnoreCase(method)){
responseModel = PartnerUtils.doPostToXianXiu(url, uToken, params);
}else if("get".equalsIgnoreCase(method)){
responseModel = PartnerUtils.doGetToXianXiu(url, uToken, params);
}
return responseModel;
}
在生成token之前会先去redis查询一遍,如果有就直接返回token,key的值可以自己去定义
(调用端和服务端操作的redis不是同一个库,这里我操作的是第一个库,服务端操作的是第三个库)
如果redis没有走生成token的流程,先生成一个随机字符串nonceStr,然后把nonceStr以及传进来的code以及secret参数进行SHA1加密得到一个签名uSign
调用getAccessToken方法进行token生成以及校验token
@Service("partnerServiceImpl")
public class PartnerServiceImpl implements PartnerService {
@Resource
private RedisService redisService;
@Override
public String getToken(String code, String secretKey) {
if(StringUtils.isEmpty(code) || StringUtils.isEmpty(secretKey)) {
return null;
}
String sessionKey = code+"-TOKEN";
String uToken = redisService.get(sessionKey);
if(StringUtils.isEmpty(uToken)) {
try {
String nonceStr=UUID.randomUUID().toString();
//进行SHA1加密
String uSign = SecuritySHA1Utils.shaEncode(code+nonceStr+secretKey);
ResponseModel responseModel = PartnerUtils.getAccessToken(code, uSign, nonceStr);
if(responseModel==null || StringUtils.isEmpty(String.valueOf(responseModel.getContent()))) {
log.info("新平台鉴权失败==================");
log.info("sign:"+uSign);
log.info("rand:"+nonceStr);
return null;
}else {
uToken = (String)responseModel.getContent();
log.info("新平台鉴权成功==================");
log.info("utoken:"+uToken);
redisService.set(sessionKey, uToken, 900);
return uToken;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}else {
return uToken;
}
}
}
//zuul网关的端口
public static String HOST = "http://localhost:8110";
//生成token的接口
public static final String TOKEN_PATH = "/partner/auth/safty/get-partner-token";
public static ResponseModel getAccessToken(String code, String signature, String nonceStr) {
String backData = "";
String param="code="+code+"&signature="+signature+"&nonceStr="+nonceStr+"";
try {
backData = HttpUtils.sendGet(HOST+TOKEN_PATH, param);
}catch (Exception e) {
e.printStackTrace();
}
log.info("============》获取accessToken"+JSON.toJSONString(backData));
// String accessToken = (String)
// JSONObject.fromObject(backData).get("access_token");
ResponseModel responseModel = JSON.parseObject(backData, new TypeReference<ResponseModel>() {
});
return responseModel;
}
网关配置
一般会把所有的请求前缀进行配置;如果出现非法请求则会被拒;强烈要求接口以前缀进行分组这样比较直观
请求合法会执行doAccess方法,把RequestContext对象,prefix请求前缀,url传入。进行鉴权
@SuppressWarnings("serial")
private static final Set<String> URL_PREFIX = new HashSet<String>() {
{
add("auth");
add("demo");
add("user");
add("job");
add("partner");
add("activity");
add("payment");
add("product");
add("hatch");
}};
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest