REST 设计原则是statelessness的,而且但客户端是APP时,从APP发起的请求,不是基于bowers,无法带相同的sessionid,所以比较好的方案是每次请求都带一个accesstoken进行验证。然后后台是根据token 找到用户,然后找到用户资源

但总不能每个方法都去调用token验证的方法,也不能每次验证都需要查询数据库吧!

解决办法:

  • 为了业务层只关注业务,所以需要把token验证的方法在进入controller前集中处理,用 Interceptor实现

  • 由于根据token获得用户,只需要用到 用户ID,用户登录名等 不会改变的信息,用缓存实现,需要支持过期失效,ConcurrentHashMap没有过期失效的功能,自己懒得实现就用ehcache

集中处理token

interceptor实现:

/**
* 验证token有效性
*/
@Component
public class AccessTokenVerifyInterceptor extends HandlerInterceptorAdapter {
@Resource
UserService userService; private final static Logger LOG = LoggerFactory.getLogger(AccessTokenVerifyInterceptor.class); @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
LOG.debug("AccessTokenVerifyInterceptor executing.......");
boolean flag = false;
//accesstoken 参数
String accessToken = request.getParameter("accesstoken");
if(StringUtils.notEmpty(accessToken)) {
//验证accessToken
//verifyAccessToken 已做缓存处理
User user = userService.verifyAccessToken(accessToken);
if(user!=null){
flag = true;
//塞到request中去,供controller里面调用
request.setAttribute(SystemConstants.SESSION_NAME_USER,user);
}
} if(!flag){
response.setStatus(HttpStatus.FORBIDDEN.value());
response.getWriter().print("wrong access token");
}
return flag;
}
}

然后到spring配置文件中加上这个拦截器:

<!--过滤器-->
<mvc:interceptors>
<!--API ACCESS TOKEN INTERCEPTOR-->
<mvc:interceptor>
<mvc:mapping path="/api/**"/>
<mvc:exclude-mapping path="/**/api/user/**" />
<mvc:exclude-mapping path="/**/api/accesstoken" />
<bean class="cn.ifengkou.athena.controller.interceptor.AccessTokenVerifyInterceptor"></bean>
</mvc:interceptor>
<!--other interceptor -->
</mvc:interceptors>

缓存处理

pom.xml中加入ehcache包:(spring集成ehcache ,需要spring-context和spring-context-support)

		<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.0</version>
</dependency>

加入ehcache.xml,大部分都是默认,参考springside里面说的,改了updateCheck="false",

<ehcache updateCheck="false"
monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir" />
<cache name="accessTokenUser"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap" />
</cache>
</ehcache>

开启缓存,在spring配置文件中加入:

<!-- 缓存配置 -->
<!-- 启用缓存注解功能(请将其配置在Spring主配置文件中) -->
<cache:annotation-driven cache-manager="cacheManager" /> <!-- Spring自己的基于java.util.concurrent.ConcurrentHashMap实现的缓存管理器(该功能是从Spring3.1开始提供的) -->
<!-- <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches"> <set> <bean name="myCache" class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"/>
</set> </property> </bean> -->
<!-- 若只想使用Spring自身提供的缓存器,则注释掉下面的两个关于Ehcache配置的bean,并启用上面的SimpleCacheManager即可 -->
<!-- Spring提供的基于的Ehcache实现的缓存管理器 -->
<bean id="cacheManagerFactory"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="cacheManagerFactory" />
</bean>

对verifyAccessToken 方法做缓存处理,也就是在原有方法上加Cacheable注解:

@Cacheable(value = "accessTokenUser",key = "#accessToken")
@Override
public User verifyAccessToken(String accessToken) {
LOG.debug("verifyAccessToken executing......");
List<User> users = userDao.getUserByAccessToken(accessToken);
if(users.size()!=1){
if(users.size()>1){
LOG.error("accessToken 出现了重复,bug!请检查!");
}
return null;
}
return users.get(0);
}

开始run出现 java.io.NotSerializableException: cn.ifengkou.athena.model.User

User 实现序列化,再试:

前端请求三次的日志,可以看到verifyAccessToken只执行了一次

2015-12-04 15:25:56,531 INFO [cn.ifengkou.athena.controller.interceptor.AccessTokenVerifyInterceptor] - <AccessTokenVerifyInterceptor executing.......>
2015-12-04 15:25:56,628 INFO [cn.ifengkou.athena.service.impl.UserServiceImpl] - <verifyAccessToken executing......>
2015-12-04 15:26:21,838 INFO [cn.ifengkou.athena.controller.interceptor.AccessTokenVerifyInterceptor] - <AccessTokenVerifyInterceptor executing.......>
2015-12-04 15:26:29,184 INFO [cn.ifengkou.athena.controller.interceptor.AccessTokenVerifyInterceptor] - <AccessTokenVerifyInterceptor executing.......>

如有token无效,查出来User为null,cache 把null也缓存起来了

keywords:

REST,accesstoken,权限,spring,ehcache,interceptor

备注:

转载请附带原文路径:http://www.cnblogs.com/sloong/p/5157654.html

REST API 基于ACCESS TOKEN 的权限解决方案的更多相关文章

  1. REST API 基于ACCESS TOKEN

    REST API 基于ACCESS TOKEN 的权限解决方案   REST 设计原则是statelessness的,而且但客户端是APP时,从APP发起的请求,不是基于bowers,无法带相同的se ...

  2. 使用Azure Rest API获得Access Token介绍

    背景 本文主要介绍如何获取如何获取Azure Rest API的访问token,所采用的是v2.0版本的Microsoft标识平台,关于1.0和2.0的区别可以参考 https://docs.azur ...

  3. ASP.NET Core 实战:基于 Jwt Token 的权限控制全揭露

    一.前言 在涉及到后端项目的开发中,如何实现对于用户权限的管控是需要我们首先考虑的,在实际开发过程中,我们可能会运用一些已经成熟的解决方案帮助我们实现这一功能,而在 Grapefruit.VuCore ...

  4. 怎样用Google APIs和Google的应用系统进行集成(4)----获得Access Token以通过一些Google APIs的OAuth2认证

    在上篇文章中: "怎样用Google APIs和Google的应用系统进行集成(3)----调用发现Google APIs的RESTful的服务"一文中,我们直接用jdk的java ...

  5. SharePoint Online 使用 adal js 获取access token

    最近在写一些SharePoint 的sample code, 有兴趣的小伙伴可以查看我的GitHub. 今天给大家介绍SharePoint Framework (SPFx  )web part 当中怎 ...

  6. Web API与OAuth:既生access token,何生refresh token

    在前一篇博文中,我们基于 ASP.NET Web API 与 OWIN OAuth 以 Resource Owner Password Credentials Grant 的授权方式( grant_t ...

  7. 微信开发-ACCESS TOKEN 过期失效解决方案

    微信开发-ACCESS TOKEN 过期失效解决方案 起因:因为access_token的重要性,开发过微信的都知道,但是他有自己的生命周期,官方解释为:"有效期为7200秒",一 ...

  8. 基于.Net Framework 4.0 Web API开发(4):ASP.NET Web APIs 基于令牌TOKEN验证的实现

    概述:  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是在使用API的时候总会遇到跨域请求的问题, ...

  9. vue基于d2-admin的RBAC权限管理解决方案

    前两篇关于vue权限路由文章的填坑,说了一堆理论,是时候操作一波了. vue权限路由实现方式总结 vue权限路由实现方式总结二 选择d2-admin是因为element-ui的相关开源项目里,d2-a ...

随机推荐

  1. winform 打包部署

    1.使用VS 自带的打包工具,制作winform安装项目 开发环境:VS 2008 Access 操作系统:Windows XP 开发语言:C# 步骤: 第一步:打开开发环境VS2008,新建项目,选 ...

  2. C#中sizeof的用法实例分析

    这篇文章主要介绍了C#中sizeof的用法,包括了常见的用法及注释事项,需要的朋友可以参考下.   sizeof是C#中非常重要的方法,本文就以实例形式分析C#中sizeof的用法.分享给大家供大家参 ...

  3. [leetcode]_Binary Tree Inorder Traversal

    题目:二叉树的中序遍历. 思路:用递归来写中序遍历非常简单.但是题目直接挑衅说,----->"Recursive solution is trivial".好吧.谁怕谁小狗. ...

  4. [leetcode]_Best Time to Buy and Sell Stock I && II

    一个系列三道题,我都不会做,google之答案.过了两道,第三道看不懂,放置,稍后继续. 一.Best Time to Buy and Sell Stock I 题目:一个数组表示一支股票的价格变换. ...

  5. pm2 开机自启动如何弄?

    1.使用pm2启动node :# pm2 start /home/wwwroot/web.js --watch 2.dump这些进程列表:# pm2 save 3.生成自启动脚本:# pm2 star ...

  6. C# 平时碰见的问题【1】

    1. SqlBulkCopy 可以利用这个类实现快速大批量新增数据的效果, 但在使用过程中发现了一个问题: 无法将数据源中的DateTime类型转换成数据库中的int类型 看起来就是数据列不对应导致的 ...

  7. Requests:Python HTTP Module学习笔记(一)(转)

    Requests:Python HTTP Module学习笔记(一) 在学习用python写爬虫的时候用到了Requests这个Http网络库,这个库简单好用并且功能强大,完全可以代替python的标 ...

  8. 关于消除超长的case列表的一个思路

    最近项目里面涉及和低层通信的一个模块,因为需要定义通信协议,然后一大堆指令,定义一个枚举的话就能看到几十上百的数据项,匹配操作的时候,那么问题来了,尼玛,这么多的case看着就头晕,就有了一个想法:怎 ...

  9. 说说用C语言求根的那些事儿

    C语言--求根:计算机只识别0和1,那么问题来了,作为计算工具如何解决数学问题?其实,计算机是死东西,都是程序员用计算机的的思维去加数学公式计算数学题的.听起来好高端的样子,其实啊,也就那么回事儿, ...

  10. hdu 2066 一个人的旅行

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2066 一个人的旅行 Description 虽然草儿是个路痴(就是在杭电待了一年多,居然还会在校园里迷 ...