一、 概述
公司项目需求在Web系统增加App接口。
二、 技术框架
后台:Spring MVC,redis
App: uni-app
App鉴权方法:App请求登录-后台校验用户名和密码—生成token,保存token到redis,有效期30分钟,返回token给App;App非登录接口携带token请求,后台校验token有效性,如果有效则刷新token有效时间,如果无效则拒绝请求并提示重新登录。
三、 步骤
3.1 思路
在后台新建一个拦截器,在拦截器中校验App请求URL,并对token进行鉴权,如果鉴权通过,则放行当前接口请求。登录接口直接放行。
3.2 新建拦截器
public class UniAppInterceptor implements HandlerInterceptor {
private static final Logger logger = Logger.getLogger(UniAppInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
logger.info("<<<<<<<<<<<<<preHandle");
String requestUri = request.getRequestURI();
String contextPath = request.getContextPath();
String url = requestUri.substring(contextPath.length());
if(url.startsWith("/uniapp/")){
// 放行登录接口
if(url.startsWith("/uniapp/auth/login")) {
return true;
}
// 其他App接口校验token
//前端获取token(需要将验证信息放入header)
String token = JWTUtil.getHeaderToken(request);
if (token == null || "".equals(token)) {
throw new AuthException(JwtErrEnums.TOKEN_INEXISTENCE);
}
/**
验证token是否有效--无效已做异常抛出,由全局异常处理后返回对应信息
*/
String redisTokenValue = this.getTokenValueFromRedis(token);
/**
* 缓存不存在token返回没有登录
*/
if (StringUtils.isEmpty(redisTokenValue) || !token.equals(redisTokenValue)) {
response.setCharacterEncoding("UTF-8");
Json json = new Json();
json.setSuccess(false);
json.setObj(JwtErrEnums.TOKEN_INEXISTENCE.getCode());
json.setMsg("请重新登录");
response.getWriter().write(JSON.toJSONString(json));
return false;
}
/**
* 刷新token有效时间
*/
JedisUtil.setObjectValue(token, redisTokenValue, 30*60);//缓存登录对象,30分钟有效期
return true;
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
logger.info("<<<<<<<<<<<<<postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
logger.info("<<<<<<<<<<<<<afterCompletion");
}
private String getTokenValueFromRedis(String tokenKey) {
String tokenJwt = JedisUtil.getStringValue(tokenKey) == null ? "" : JedisUtil.getStringValue(tokenKey);
if (tokenJwt == null || tokenJwt.equals("")) return "";
return tokenJwt;
}
private String createRedisTokenKey(String loginName, String clientId) {
String objParam = loginName + ":" + clientId;
return RedisKeyRule.keyBuilder(RedisEnum.REDIS_KEY_REST_API_QUERYBYID, Constants.CONN_AUTH_TOKEN_MODULE, objParam);
}
}
3.3 spring-mvc.xml中配置拦截器
mvc:interceptors
mvc:interceptor
<mvc:mapping path="/uniapp/**"/>
<mvc:exclude-mapping path="/admin"/>
</mvc:interceptor>
</mvc:interceptors>
3.4 uni-App端网络请求
uni.request({
url: this.config.apiHost + “/controller/getDataTotal”,
method: ‘POST’,
sslVerify: false,
dataType: ‘json’,
timeout: 20000,
data: {
"queryValue": '',
},
header: {
'Authorization': uni.getStorageSync('accessToken'), //自定义请求头信息
},
success: (res) => {
var data = res.data;
if (data.success == true) {
} else {
uni.showModal({
content: data.msg,
showCancel: false
})
console.log('获取失败', data);
}
},
fail: (err) => {
console.log('request fail', err);
var msgContent = err.errMsg;
if ("request:fail abort statusCode:-1" == msgContent) {
// 网络差或者未连接网络
msgContent = "网络连接不可用,请检查手机网络";
}
uni.showModal({
content: msgContent,
showCancel: false
});
},
complete: () => {
this.$refs.Loading.hide()
}
});
3.5 其他
App端需要对请求失败作处理,跳转到登录界面。