(Quick Reference)
6 Token Storage - Reference Documentation
Authors: Alvaro Sanchez-Mariscal
Version: 1.4.1
6 Token Storage
The tokens are stored on the server using a
tokenStorageService
bean. The plugin comes with out-of-the-box support
for Memcached, GORM and
Grails Cache, but you can use your own strategy implementing the
TokenStorageService
interface.
6.1 Memcached
To use Memcached, simply define the following configuration properties to match your environments accordingly:
Config key | Default value |
---|
grails.plugin.springsecurity.rest.token.storage.useMemcached | false |
grails.plugin.springsecurity.rest.token.storage.memcached.hosts | localhost:11211 |
grails.plugin.springsecurity.rest.token.storage.memcached.username | '' |
grails.plugin.springsecurity.rest.token.storage.memcached.password | '' |
grails.plugin.springsecurity.rest.token.storage.memcached.expiration | 3600 |
For development, if you have Memcached installed locally with the default settings, just define
grails.plugin.springsecurity.rest.token.storage.useMemcached = true
. It should work.
In Memcached tokens will expire automatically after the configured timeout (1h by default).
They get refreshed on every access
6.2 GORM
To use GORM, these are the relevant configuration properties:
Config key | Default value |
---|
grails.plugin.springsecurity.rest.token.storage.useGorm | false |
grails.plugin.springsecurity.rest.token.storage.gorm.tokenDomainClassName | null |
grails.plugin.springsecurity.rest.token.storage.gorm.tokenValuePropertyName | tokenValue |
grails.plugin.springsecurity.rest.token.storage.gorm.usernamePropertyName | username |
The relevant domain class should look something like this:
package org.my.pathclass AuthenticationToken { String tokenValue
String username static mapping = {
version false
}
}
For the tokenDomainClassName
configuration you must enter a fully qualified class name. In the case of the example above:
grails.plugin.springsecurity.rest.token.storage.gorm.tokenDomainClassName = 'org.my.path.AuthenticationToken'
A few things to take into consideration when using GORM for token storage:
- Instead of storing the whole
UserDetails
object, probably only the username is needed. This is because applications
using this strategy will probably have the standard User and Role domain classes. When the token is verified the username
is passed to the default
userDetailsService
bean, which in the case of the default Spring Security Core GORM
implementation will fetch the information from the mentioned domain classes.
- GORM's optimistic locking feature is likely unecessary and may cause performance issues.
- You'll have to handle token expiration by yourself via Quartz jobs or a similar mechanism. There are various ways you might
go about this.
Gorm Token Expiration Examples:Adding a GORM autoTimestamp property like
lastUpdated
or
dateCreated
and sorting out stale or old tokens with Quartz jobs
are the most obvious routes. Each has its drawbacks though.
dateCreated
is useful if you want tokens to expire a set time after they are issued. However, API users who didn't pay
attention to when their token was issued may find themselves needing a new token unexpectedly.
lastUpdated
requires a change to the token domain instance in order to be triggered. Something as simple as an access
counter may work as a strategy to keepTokens fresh, but doing a write to a disk based database on each token access may
be something you would prefer to avoid for the sake of performance.
Date lastUpdated
Integer accessCount = 0 def afterLoad() {
accessCount++
}
Simply using your own date or timestamp is also a valid option.
Date refreshed = new Date() def afterLoad() {
// if being accessed and it is more than a day since last marked as refreshed
// and it hasn't been wiped out by Quartz job (it exists, duh)
// then refresh it
if (refreshed < new Date() -1) {
refreshed = new Date()
it.save()
}
}
Here is an example quartz job to go with the custom refresh timestamp above:
class RemoveStaleTokensJob {
static triggers = {
cron name: 'every4hours', cronExpression: '0 0 */4 * * *'
} void execute() {
AuthenticationToken.executeUpdate('delete AuthenticationToken a where a.refreshed < ?' [new Date()-1])
}
}
6.3 Grails Cache
To use
Grails Cache, simply define a cache name:
Config key | Default value |
---|
grails.plugin.springsecurity.rest.token.storage.useGrailsCache | false |
grails.plugin.springsecurity.rest.token.storage.grailsCacheName | null |
The cache name should correspond to a name specified in the
cache DSL.
Token expiration / eviction / TTLBy default, Spring Cache abstraction
does not support expiration.
It depends on the specific support of the actual providers. Grails has several plugins for this:
There is a bug in :cache-ehcache:1.0.0
plugin that will cause issues. It's recommended that you use the latest version.
See #89 for more information.