REST API 基于ACCESS TOKEN 的权限解决方案

 

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 设计原则是statelessness的,而且但客户端是APP时,从APP发起的请求,不是基于bowers,无法带相同的sessionid,所以比较好的方案是每次请求都带一个accesstok ...

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

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

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

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

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

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

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

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

  6. View and Data API tips: 缓存Access Token

    对于云API服务,常见的方式就是按照API调用次数收费,某些API调用也就有某些限制,比如在特定时间内只允许调用指定的次数以免造成滥用.虽然Autodesk的view and Data API目前还没 ...

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

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

  8. gitlab克隆报错:remote: HTTP Basic: Access denied;remote: You must use a personal access token with ‘api’ scope for Git over HTTP.

    错误: remote: HTTP Basic: Access denied remote: You must use a personal access token with ‘api’ scope ...

  9. 【Azure Developer】Python 获取Micrisoft Graph API资源的Access Token, 并调用Microsoft Graph API servicePrincipals接口获取应用ID

    问题描述 在Azure开发中,我们时常面临获取Authorization问题,需要使用代码获取到Access Token后,在调用对应的API,如servicePrincipals接口. 如果是直接调 ...

随机推荐

  1. Unity3D 游戏开发构架篇 ——输入控制

    临近毕业之初.进入Unity3D这个行业,是一家小工作室.老板人非常不错,公司氛围也非常单纯.近期公司开发一款小游戏,初次上手,颇多周折,记录下自己的开发心得.主要涉及一些设计理念,互相交流. 先说下 ...

  2. 李兴华JavaWeb开发笔记

    李兴华JavaWeb开发笔记 1.Java语法-基础 环境变量-JAVA_HOME, PATH, ClassPath 变量名 作用 举例 JAVA_HOME 指向JDK目录 C:\Program Fi ...

  3. LeetCode——Search a 2D Matrix

    Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the follo ...

  4. STL 源代码分析 算法 stl_algo.h -- includes

    本文senlie原,转载请保留此地址:http://blog.csdn.net/zhengsenlie includes(应用于有序区间) ------------------------------ ...

  5. Codeforces Round #252 (Div. 2) B. Valera and Fruits(模拟)

    B. Valera and Fruits time limit per test 1 second memory limit per test 256 megabytes input standard ...

  6. 【Struts2学习笔记(11)】对action的输入校验和XML配置方式实现对action的全部方法进行输入校验

    在struts2中,我们能够实现对action的全部方法进行校验或者对action的指定方法进行校验. 对于输入校验struts2提供了两种实现方法: 1. 採用手工编写代码实现. 2. 基于XML配 ...

  7. ym——Android开发编码规范(自用)

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! Android开发编码规范 目的及指导原则 目的 统一规范 Eclipse编辑环境下J ...

  8. Android 检測网络是否连接

    权限: <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>  <u ...

  9. OpenCV-Python教程(9、使用霍夫变换检测直线)

    相比C++而言,Python适合做原型.本系列的文章介绍如何在Python中用OpenCV图形库,以及与C++调用相应OpenCV函数的不同之处.这篇文章介绍在Python中使用OpenCV的霍夫变换 ...

  10. solr4.9r+ Eclipse 4.3+ tomcat 7.5 +winds7(二)

    尊重原创,原文地址:http://blog.csdn.net/chunlei_zhang/article/details/38778945 这另外一种方法是将solr项目部署到tomcat上,执行to ...