Server端通过集成Spring Security Rest插件使用Spring Security进行无状态,基于JWT的RESTful身份验证。
- 添加支持(build.gradle):
compile "org.grails.plugins:spring-security-rest:2.0.0.RC1"
- 创建domain类:
s2-quickstart com.vue.grails.demo BaseUser BaseRole Requestmap
- 配置(application.groovy)
// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.vue.grails.demo.BaseUser'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.vue.grails.demo.BaseUserBaseRole'
grails.plugin.springsecurity.authority.className = 'com.vue.grails.demo.BaseRole'
grails.plugin.springsecurity.requestMap.className = 'com.vue.grails.demo.Requestmap'
grails.plugin.springsecurity.securityConfigType = 'Requestmap'
grails.plugin.springsecurity.filterChain.chainMap = [
//Stateless chain
[
pattern: '/**',
filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'
],
//Traditional, stateful chain
[
pattern: '/stateful/**',
filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
]
]
// 注意
grails.plugin.springsecurity.rest.token.storage.jwt.secret = '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222'
ps:配置grails.plugin.springsecurity.conf.rest.token.storage.jwt.secret
属性出现的问题及解决步骤:
(1). 官网说明在文档中说明属性grails.plugin.springsecurity.conf.rest.token.storage.jwt.secret
不在有默认值,使用JWT并且没有为该配置属性提供任何值,则在应用程序启动期间将引发异常。

(2). 按照
grails.plugin.springsecurity.conf.rest.token.storage.jwt.secret
配置后启动项目仍然抛出了异常如下:
java.lang.Exception: A JWT secret must be defined. Please provide a value for the config property: grails.plugin.springsecurity.conf.rest.token.storage.jwt.secret
(3). 是什么情况呢?通过添加断点进行debug后发现SpringSecurityRestGrailsPlugin.groovy
中获取的jwtSecretValue值为null,如下图:


(4). 那么我们定义的属性去哪里,继续查看conf在最后发现另一个conf,里面是我们定义的值,如下图:

所以分析只需要将
grails.plugin.springsecurity.conf.rest.token.storage.jwt.secret
中的conf
去掉即可。
- 初始化角色用户(Bootstrap.groovy)
package vue.grails.demo
package vue.grails.demo
import com.vue.grails.demo.BaseRole
import com.vue.grails.demo.BaseUser
import com.vue.grails.demo.BaseUserBaseRole
import com.vue.grails.demo.Requestmap
class BootStrap {
def springSecurityService
def init = { servletContext ->
createDefaultRoles()
createDefaultUsers()
createRequestmap()
}
def destroy = {
}
private void createDefaultRoles() {
if (!BaseRole.findByAuthority('ROLE_ADMIN')){
new BaseRole(authority:'ROLE_ADMIN').save(flush: true)
}
}
private void createDefaultUsers() {
if (!BaseUser.findByUsername('admin')) {
def admin = new BaseUser(username:'admin', password: '123456')
admin.save(flush: true)
BaseUserBaseRole.create(admin,BaseRole.findByAuthority('ROLE_ADMIN'),true);
}
}
private void createRequestmap() {
if (Requestmap.count() == 0) {
for (String url in [
'/error', '/index', '/index.gsp', '/**/favicon.ico', '/shutdown',
'/assets/**', '/**/js/**', '/**/css/**', '/**/images/**',
'/login', '/login.*', '/login/*',
'/logout', '/logout.*', '/logout/*',
'/api/login', '/api/validate', '/api/logout']) {
new Requestmap(url: url, configAttribute: 'permitAll').save()
}
new Requestmap(url: '/api/**', configAttribute: 'isFullyAuthenticated()').save(flush: true)
new Requestmap(url: '/**', configAttribute: 'isFullyAuthenticated()').save(flush: true)
springSecurityService.clearCachedRequestmaps()
}
}
}
- 测试
(1). 浏览器直接访问http://localhost:8080/
,返回401,如下图:
401.png
(2). post方式访问http://localhost:8080/api/login
进行模拟登录,认证成功后返回token,如下图:

返回的json里包含username、roles、token_type、access_token、expires_in、refresh_token
(3).携带生成的token访问http://localhost:8080/
,可以得到数据,如下图:

网友评论