实现技术:AOP
认证描述:实现API访问认证。
首先任何一个API访问都需要经过认证中心进行认证,认证通过之后可以进行访问,认证失败跳转登录界面。认证通过访问者携带的token和待访问API进行认证。未携带token,token过期,API未在权限内都将被拦截。
登录时,用户通过用户名和密码认证,正确后服务器返回给用户token
具体细节
登录
通过用户名和密码进行验证,验证成功之后对token进行操作。将token的LoginName 设置为userName
//生成Token
UUID tokenName = UUID.randomUUID();
//更新数据库
token = new Token();
token.setLoginName(userName);
token.setTokenName(tokenName.toString());
//得到当前系统时间
Timestamp timeNow = new Timestamp(new Date().getTime());
token.setCreateTime(timeNow);
//有效时间
token.setEffectiveTime(effectTime);//之前已经将effectTime设置为20分钟
之后通过userName 验证token中是否已存在登录用户的记录,若存在则更新(按照userName更新),若不存在,则插入一条新数据。
if(tokenService.findByLoginName(userNmae)==null){
tokenService.insert(token);
}else{
tokenService.updateByPrimaryKeySelective(token);
}
登录完成后,后台将token的tokenName传给前台。
2.验证 登录之后,用户就可以“拿着”token去访问API了。
在访问任何API前(登录除外),请求都将经过认证,认证的流程就是通过用户所携带的token以及API来查询该用户是否有访问其待访问API的权限。
具体实现方法是利用AOP技术中的环绕通知在controller执行前进行拦截认证。对AOP不了解的参看这里
由于AOP的思想是面向切面编程,所以只需要确定好切点,并把切面中要做的事情描述完善即可。
首先确定好切入点
@Pointcut("execution(* com.authority.controller..(..))")
public void pointCut() {}
确定通知方法,采用环绕通知@Around。 @Around("pointCut()") public Object roung(ProceedingJoinPoint pj)//ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
接着就是详细的认知操作了,先获取token 和API。
String tokenName = request.getHeader("token");//token被储存在header中
String url = request.getRequestURI();
String method = request.getMethod();
按照数据库中API的存储格式对获取到的URL和method进行解析。对于带有参数的URL会最后解析为/0/方便识别。
然后根据获取到的token查找是否存在
Token token = tokenService.findByTokenName(tokenName);
if(token == null) return "{‘result‘:‘Token not exists‘}";
之后判断token是否过期
Timestamp createTime = token.getCreateTime();//获取token创建时间
int len = token.getEffectiveTime();//获取token有效时长
Timestamp timeNow = new Timestamp(new Date().getTime());//获取当前时间
//通过token的创建时间和有效时长进行计算与当前时间进行比较
if((createTime.getTime()+len100060) >= timeNow.getTime()){
...//后续操作
}else{return "{‘result‘:‘The token is timeout !!!‘}";}
最后验证是否有权限访问API。
allApi = authorityService.getAPI(tokenName);//获取可以访问的API
if(allApi!=null && allApi.contains(tooString)){//查看是否有访问待访问API权限
return pj.proceed();//执行目标方法
}