REST API 基于ACCESS TOKEN
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
备注:
REST API 基于ACCESS TOKEN的更多相关文章
- REST API 基于ACCESS TOKEN 的权限解决方案
REST 设计原则是statelessness的,而且但客户端是APP时,从APP发起的请求,不是基于bowers,无法带相同的sessionid,所以比较好的方案是每次请求都带一个accesstok ...
- 使用Azure Rest API获得Access Token介绍
背景 本文主要介绍如何获取如何获取Azure Rest API的访问token,所采用的是v2.0版本的Microsoft标识平台,关于1.0和2.0的区别可以参考 https://docs.azur ...
- SharePoint Online 使用 adal js 获取access token
最近在写一些SharePoint 的sample code, 有兴趣的小伙伴可以查看我的GitHub. 今天给大家介绍SharePoint Framework (SPFx )web part 当中怎 ...
- 怎样用Google APIs和Google的应用系统进行集成(4)----获得Access Token以通过一些Google APIs的OAuth2认证
在上篇文章中: "怎样用Google APIs和Google的应用系统进行集成(3)----调用发现Google APIs的RESTful的服务"一文中,我们直接用jdk的java ...
- Web API与OAuth:既生access token,何生refresh token
在前一篇博文中,我们基于 ASP.NET Web API 与 OWIN OAuth 以 Resource Owner Password Credentials Grant 的授权方式( grant_t ...
- View and Data API tips: 缓存Access Token
对于云API服务,常见的方式就是按照API调用次数收费,某些API调用也就有某些限制,比如在特定时间内只允许调用指定的次数以免造成滥用.虽然Autodesk的view and Data API目前还没 ...
- 基于.Net Framework 4.0 Web API开发(4):ASP.NET Web APIs 基于令牌TOKEN验证的实现
概述: ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是在使用API的时候总会遇到跨域请求的问题, ...
- 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 ...
- 【Azure Developer】Python 获取Micrisoft Graph API资源的Access Token, 并调用Microsoft Graph API servicePrincipals接口获取应用ID
问题描述 在Azure开发中,我们时常面临获取Authorization问题,需要使用代码获取到Access Token后,在调用对应的API,如servicePrincipals接口. 如果是直接调 ...
随机推荐
- Bdsyn百度手机助手是何物,它是怎样神不知鬼不觉地安装到你的电脑里的?
[电脑软件管理中Bdsyn手机助手的问题]Bdsyn手机助手 is developed by Baidu, Inc. and is used by 10 users of Software Infor ...
- JAVA中enum的常见用法
JAVA中enum的常见用法包括:定义并添加方法.switch.遍历.EnumSet.EnumMap 1.定义enum并添加或覆盖方法 public Interface Behaviour{ void ...
- nginx+tomcat负载均衡策略
測试环境均为本地,測试软件为: nginx-1.6.0,apache-tomcat-7.0.42-1.apache-tomcat-7.0.42-2.apache-tomcat-7.0.42-3 利用n ...
- Android真机网络adb联机调试初探
新项目是一个基于android4.2设备.刚拿到demo板时就对联机互调感兴趣了.处于以前在S3c2440上对linux的移植使用经验.心里猜测对于android设备应该也这样.所以通过搜索资料整理如 ...
- vim php代码规范
vim 代码规范工具php-cs-fixer.phar (參考https://github.com/FriendsOfPHP/PHP-CS-Fixer) INSTALL curl http://get ...
- WPF案例 (四) 模拟Windows7桌面任务栏
原文:WPF案例 (四) 模拟Windows7桌面任务栏 这个程序模彷了Windows7的桌面任务栏,当在桌面上双击某个快捷方式时,将打开一个新的子界面,并且在任务栏里创建一个链接到此界面的任务栏图标 ...
- python中print,return和yield的区别
def func1(): for i in range(1, 5): print i def func2(): for i in range(1, 5): return i def func3(): ...
- grails的controller和action那点事---远程调试groovy代码
最近由于项目需要,用到了grails,这玩意确实好用,生产率高有类型python的速度与简洁.仅第一印象,用的还不深入,说的不对请轻拍. 遇到的几个问题: 1. groovy远程调试 玩Java的应该 ...
- If you pay peanuts,you get monkeys
英文原文:Before you send an email to contact a web developer, please read this… 做为一名开发者,我收到很多关于开发新 web 应 ...
- Hdu 4539 【状态DP】.cpp
题意: 一个炮兵可以攻打和他之间曼哈顿距离为2的士兵,给出你一块n*m的战场,告诉你哪些地方可以站人哪些地方不可以,问你最多可以安放多少个士兵? n <= 100, m <= 10 思路: ...