The REST design principle is statelessness, but when the client is an app, the request from the app is not based on Bowers and cannot carry the same sessionid, so the better solution is to have a accesstoken for each request. Then the background is based on token to find the user, and then find the user resources
But it is not always possible for each method to call token authentication method, or every time the validation needs to query the database it!
Workaround:
In order for the business layer to focus on the business, the token verification method needs to be centrally processed before it enters the controller and implemented with interceptor
Because according to token to obtain the user, only need to use the user ID, user login name, etc. will not change the information, with the cache implementation, need to support expiration invalidation, Concurrenthashmap no expiration function, self-lazy implementation of Ehcache
Centralize token handling
Interceptor implementation:
/** * Verify token validity */@ComponentPublicClassAccesstokenverifyinterceptorExtendsHandlerinterceptoradapter {@Resource UserService UserService;PrivateFinalstatic Logger LOG = Loggerfactory.getlogger (Accesstokenverifyinterceptor.class);@OverridePublicBooleanPrehandle(HttpServletRequest request, httpservletresponse response, Object handler)Throws Exception {Log.debug ("Accesstokenverifyinterceptor executing ...");boolean flag = FALSE; //accesstoken parameter String accesstoken = Request.getparameter ( " Accesstoken "); if (Stringutils.notempty (Accesstoken)) {//verify AccessToken Span class= "Hljs-comment" >//verifyaccesstoken has been cached to handle user user = Userservice.verifyaccesstoken (accesstoken); if (User!=null) {flag = true; Span class= "hljs-comment" >//plug into request, for controller inside call Request.setattribute (Systemconstants.session_name_user, user); }} if (!flag) {response.setstatus (HttpStatus.FORBIDDEN.value ()); Response.getwriter (). Print ( "wrong access token");} return flag;}
Then add this interceptor to the spring configuration file:
<!--Filters--<Mvc:interceptors><!--API ACCESS TOKEN interceptor--><Mvc:interceptor><Mvc:mappingpath="/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-and</mvc:interceptors>
Cache processing
Add Ehcache package in Pom.xml: (Spring integrated Ehcache, Spring-context and Spring-context-support required)
<dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.0</version> </dependency>
Add Ehcache.xml, most of them are default, reference Springside inside said, changed updatecheck= "false",
<Ehcacheupdatecheck="False"monitoring="AutoDetect"dynamicconfig="True" ><DiskstorePath="Java.io.tmpdir"/><CacheName="Accesstokenuser"maxentrieslocalheap= "10000" maxentrieslocaldisk= "1000" Span class= "hljs-attr" >eternal= "false" diskspoolbuffersizemb=< Span class= "hljs-string" > "
timetoidleseconds=
"
timetoliveseconds=
"all" Memorystoreevictionpolicy= "LFU" transactionalmode= "off" > <persistence Strategy= "Localtempswap"/> </ Cache></EHCACHE>
Open the cache and include in the spring configuration file:
<!--cache configuration--<!--enable the cache annotation feature (please configure it in the Spring Master profile)--<Cache:annotation-drivenCache-manager="CacheManager"/><!--Spring's own Java.util.concurrent.ConcurrentHashMap-based cache manager (which is provided starting from 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 ><!--If you want to use only the buffers provided by spring itself, comment out the following two beans on the Ehcache configuration and enable the Simplecachemanager above.<!--Spring provides a cache manager based on the Ehcache implementation--<BeanId="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>
The
Verifyaccesstoken method is cached, which means adding cacheable annotations to the original method:
@Cacheable (value = "Accesstokenuser", Key = "#accessToken") @override Public User verifyaccesstoken (string accesstoken) {LOG.debug ( Span class= "hljs-string" > "Verifyaccesstoken executing ..."); list<user> users = Userdao.getuserbyaccesstoken (Accesstoken); if (users.size ()!=1) {if ( Users.size () >1) {log.error (return null;} return users. get (0);
Start Run appears Java.io.NotSerializableException:cn.ifengkou.athena.model.User
The User implements serialization, and then tries:
Front-end Request three logs, you can see that Verifyaccesstoken only performed one time
2015-12-04 15: 25: 56,531INFO[Cn.ifengkou.athena.controller.interceptor.AccessTokenVerifyInterceptor]-<Accesstokenverifyinterceptorexecuting.......>2015-12-04 15: 25: 56,628INFO[Cn.ifengkou.athena.service.impl.UserServiceImpl]-<Verifyaccesstokenexecuting......>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] -<< Span class= "Hljs-selector-tag" >accesstokenverifyinterceptor executing.......>
If token is invalid, find out that user is Null,cache null is also cached.
Keywords
Rest,accesstoken, permissions, Spring,ehcache,interceptor
Note:
Reprint please accompany the original path: http://www.cnblogs.com/sloong/p/5157654.html
REST API is based on access TOKEN