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

备注:

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

时间: 2024-10-14 05:52:56

REST API 基于ACCESS TOKEN的相关文章

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

在前一篇博文中,我们基于 ASP.NET Web API 与 OWIN OAuth 以 Resource Owner Password Credentials Grant 的授权方式( grant_type=password )获取到了 access token,并以这个 token 成功调用了与当前用户(resource owner)关联的 Web API. 本以为搞定了 access token 就搞定了 Web API 的验证与授权问题,可是发现 OAuth 中还有一种 token,叫 r

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

概述:  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是在使用API的时候总会遇到跨域请求的问题, 特别各种APP万花齐放的今天,对API使用者身份角色验证是不能避免的(完全开发的API不需要对使用者身份角色进行管控,可以绕过),这篇文章就来谈谈基于令牌TOKEN身份验证的实现. 问题: 对于Web API的选择性的开放,使用者无论使用AJAX,还是HttpClient对接,总要对使用者的身份角色

View and Data API tips: 缓存Access Token

对于云API服务,常见的方式就是按照API调用次数收费,某些API调用也就有某些限制,比如在特定时间内只允许调用指定的次数以免造成滥用.虽然Autodesk的view and Data API目前还没有应用这样的限制,但我们最好也能实现这样的机制,比如对于或者Access Token这样的操作,一个Access Token是有一定的有效期的,在这个token的有效期内,我们就没必要重复发出API调用获取新的Acces Token,只有返回仍然有效的token就可以了.下面是c#实现的简单的逻辑,

personal access token 访问 git api

git api存储了很多有用的仓库信息可供大家查阅,而且最重要的是你可以把它爬下来搞一搞,用python可以轻松的做到这一点,然而访问git api的时候会有一个访问限制,没有认证的访问每小时只能进行60次...所以需要认证一下. 比较简单的办法就是在requsets中加入参数,参数为你的client_id 和 client_secret.这里用python演示: response=requsets.get('https://api.github.com/repos/your_name/your

微信公众号开发Access Token

Access Token 在微信公众平台接口开发中,Access Token占据了一个很重要的地位,相当于进入各种接口的钥匙,拿到这个钥匙才有调用其他各种特殊接口的权限. access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效. 公众号可以使用AppID和AppSecret调用本接口来获取access_token.AppID和AppSecret可

使用缓存Memcache存储更新微信access token

关键字:Memcache access_token 更新 存储 7200 本文介绍如何使用缓存Memcache存储及更新 access token的方法. 一.Access Token access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效. 公众号可以使用AppID和AppSecret调用本接口来获取access_token.AppID和App

OAuth2.0 微博登陆网站功能的实现(一)获取用户授权及令牌 Access Token

在登陆一些网站的时候,可以选择登陆方式为第三方登陆,例如微博登陆,以爱奇艺为例,进入首页,点击 ”登陆“,会弹出登录框: 除了本站登陆外,还可以选择其他第三方登陆,比如微博登陆.QQ 登陆.微信登陆等. 选择微博登陆后,爱奇艺会向用户申请授权用于微博登陆(当用户已经登陆了微博时会直接申请授权,当用户没有登陆时会提示用户登陆微博): 此时提示窗口的 url 为:https://api.weibo.com/oauth2/authorize?scope=&redirect_uri=http%3A%2F

ASP.NET OAuth:解决refresh token无法刷新access token的问题

最近同事用iOS App调用Open API时遇到一个问题:在access token过期后,用refresh token刷新access token时,服务器响应"invalid_grant"错误:而在access token没有过期的情况下,能正常刷新access token. 先查看了一下OAuth规范中的“Refreshing an Expired Access Token”流程图,以确认客户端的操作流程有没有问题. 问题发生在上图中的(G)操作步骤.iOS App就是按上图的

PHP CURL获取微信公众平台的ACCESS TOKEN以及创建菜单的方法

//使用curl模块,必须在php.in 里面将curl模块开启.<?php header("Content-type: text/html; charset=utf-8"); define("app_id","xxx");//APP_ID define("app_secret","xxxx");//APP_SECRET //获取access token 的方法 function get_access