Grails 2.5.4 / Spring Security Rest 1.5.4 - 验证令牌
Grails 2.5.4 / Spring Security Rest 1.5.4 - Validating token
我想做的是登录用户并取回令牌(这部分有效)。然后我想在每次访问 API 路径时验证此令牌。我显然做错了什么,也许我不完全理解 Spring Security Rest 插件实际上应该做什么,但是每当我调用 API 路径并发送令牌时,我得到的只是Spring 安全登录页面的 html。我正在使用 Boomerang Soap 和 Rest Client。这是我要发送的内容。
登录请求(路径:http://localhost:7070/backend3/api/login
):
{
"username": "test@user.com",
"password": "1234"
}
登录响应:
{
"username": "test@user.com",
"roles": [
"ROLE_USER"
],
"token_type": "Bearer",
"access_token": "eyJhbGciOiJIU.", // shortened token to conserve space
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJIU." // shortened token to conserve space
}
很明显这部分工作正常。然后我尝试使用从上述响应中收到的令牌来访问我的 API。请记住,在我的 Spring 安全规则下的配置中,我有 '/external/**':['ROLE_USER']
。如果我将其更改为 ['permitAll']
那么我就可以毫无问题地访问它,但是 spring 安全性实际上是无用的。
API请求(路径:http://localhost:7070/backend3/external/user/info
)
{
"access_token": "eyJhbGciOiJIU" // shortened token to conserve space
}
这就是 return 的标准登录页面 html。我试过发送各种东西的组合,例如 access_token
、username
、token_type
、roles
。我什至尝试了不同格式的 access_token
; "Authorization":"Bearer eyJhbGciOiJIU"
我在 docs 上找到的,但没有任何效果。
有人可以向我解释如何解决这个问题吗,因为文档假设了很多我显然不具备的先验知识。我将在下面 post(相关部分)我的 Config 和 UrlMappings 文件进行进一步说明。如果我需要提供更多信息,请告诉我,我真的需要让它工作,因为我已经坚持了 2 周。谢谢
配置:
// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.crastino.domain.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.crastino.domain.UserRole'
grails.plugin.springsecurity.authority.className = 'com.crastino.domain.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
'/': ['permitAll'],
'/index': ['permitAll'],
'/index.gsp': ['permitAll'],
'/assets/**': ['permitAll'],
'/**/js/**': ['permitAll'],
'/**/css/**': ['permitAll'],
'/**/images/**': ['permitAll'],
'/**/favicon.ico': ['permitAll'],
'/external/**': ['ROLE_USER']
]
grails.plugin.springsecurity.filterChain.chainMap = [
'/auth/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter', // Stateless chain
'/api/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter', // Stateless chain
'/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
]
grails.plugin.springsecurity.rest.login.active=true
grails.plugin.springsecurity.rest.login.endpointUrl='/api/login'
grails.plugin.springsecurity.rest.login.failureStatusCode=401
grails.plugin.springsecurity.rest.login.useJsonCredentials=true
grails.plugin.springsecurity.rest.login.usernamePropertyName='username'
grails.plugin.springsecurity.rest.login.passwordPropertyName='password'
grails.plugin.springsecurity.rest.logout.endpointUrl='/auth/logout'
grails.plugin.springsecurity.rest.token.generation.useSecureRandom=true
grails.plugin.springsecurity.rest.token.generation.useUUID=false
grails.plugin.springsecurity.rest.token.validation.active=true
grails.plugin.springsecurity.rest.token.validation.endpointUrl='/auth/validate'
Ps。我还尝试通过将 '/external/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
添加到数组
的末尾来添加我试图访问此部分的路径 grails.plugin.springsecurity.filterChain.chainMap
网址映射:
group("/external") {
"/user/info" (controller: 'external', action: 'Service_UserInfo')
}
似乎问题是:您的 url http://localhost:7070/backend3/external/user/info
不在 /api/** 下,因此正在调用常规 spring 安全过滤器链而不是其余 api 个过滤器链。
尝试
/external/**: 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter'
同样默认使用不记名令牌。所以你必须在授权 header 中传递持有者令牌,除非你更改了 header 名称并禁用了持有者令牌。
我的老板设法让它为我工作。主要问题似乎是我试图访问的控制器。控制器现在看起来像这样:
// package statement
// import statements
import grails.rest.RestfulController
class UserController extends RestfulController<User> {
def springSecurityService
static responseFormats = ['json', 'xml']
UserController() {
super(User)
}
@Secured(['permitAll'])
def index() {
// use this method to test the api without authenticating
// if you are authenticated though, it'll let you know.
if(springSecurityService.isLoggedIn()) {
render(text:[loggedIn:'true'] as JSON)
} else {
render(text:[loggedIn:'false'] as JSON)
}
}
@Secured(['ROLE_USER'])
def listContacts() {
// needs authentication to access so if you call this method
// through the api and it returns users you're golden
def result = User.findAll()
respond result, [excludes: ['class']]
}
}
所以关键区别似乎是导入和扩展 RestfulController、responseFormats 和构造函数。我实际上并不知道这意味着什么或它是如何工作的,所以如果有人想编辑对此答案的解释,请拜访我。
我犯的另一个主要错误是在休息电话中。我会用我的 username/password 作为 json 参数调用 /api/login,这 return access_token
没问题。但是当我想访问时,例如,/user/listContacts,我会将 access_token
作为带有键 access_token
的参数发送,而不是将其作为带有键 header 的参数发送=15=]。这样做似乎是修复的一部分。
我的老板还删除了我的配置文件中的大部分废话(与 Spring 安全和休息相关),所以我也将提供这些更改。请注意,控制器、配置和 API 调用是唯一必要的更改,因此您项目中的所有其他内容都可以保持标准(除了在您的 BuildConfig 中包含插件)。
//Config for Spring Security REST plugin
//login
grails.plugin.springsecurity.rest.login.useJsonCredentials = true
grails.plugin.springsecurity.rest.token.storage.useGorm = true
grails.plugin.springsecurity.rest.token.storage.gorm.tokenDomainClassName = 'com.crastino.domain.AuthenticationToken'
就是这样。此外,here's 一个 link 的示例项目很有帮助。
就是这样。
我想做的是登录用户并取回令牌(这部分有效)。然后我想在每次访问 API 路径时验证此令牌。我显然做错了什么,也许我不完全理解 Spring Security Rest 插件实际上应该做什么,但是每当我调用 API 路径并发送令牌时,我得到的只是Spring 安全登录页面的 html。我正在使用 Boomerang Soap 和 Rest Client。这是我要发送的内容。
登录请求(路径:http://localhost:7070/backend3/api/login
):
{
"username": "test@user.com",
"password": "1234"
}
登录响应:
{
"username": "test@user.com",
"roles": [
"ROLE_USER"
],
"token_type": "Bearer",
"access_token": "eyJhbGciOiJIU.", // shortened token to conserve space
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJIU." // shortened token to conserve space
}
很明显这部分工作正常。然后我尝试使用从上述响应中收到的令牌来访问我的 API。请记住,在我的 Spring 安全规则下的配置中,我有 '/external/**':['ROLE_USER']
。如果我将其更改为 ['permitAll']
那么我就可以毫无问题地访问它,但是 spring 安全性实际上是无用的。
API请求(路径:http://localhost:7070/backend3/external/user/info
)
{
"access_token": "eyJhbGciOiJIU" // shortened token to conserve space
}
这就是 return 的标准登录页面 html。我试过发送各种东西的组合,例如 access_token
、username
、token_type
、roles
。我什至尝试了不同格式的 access_token
; "Authorization":"Bearer eyJhbGciOiJIU"
我在 docs 上找到的,但没有任何效果。
有人可以向我解释如何解决这个问题吗,因为文档假设了很多我显然不具备的先验知识。我将在下面 post(相关部分)我的 Config 和 UrlMappings 文件进行进一步说明。如果我需要提供更多信息,请告诉我,我真的需要让它工作,因为我已经坚持了 2 周。谢谢
配置:
// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.crastino.domain.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.crastino.domain.UserRole'
grails.plugin.springsecurity.authority.className = 'com.crastino.domain.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
'/': ['permitAll'],
'/index': ['permitAll'],
'/index.gsp': ['permitAll'],
'/assets/**': ['permitAll'],
'/**/js/**': ['permitAll'],
'/**/css/**': ['permitAll'],
'/**/images/**': ['permitAll'],
'/**/favicon.ico': ['permitAll'],
'/external/**': ['ROLE_USER']
]
grails.plugin.springsecurity.filterChain.chainMap = [
'/auth/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter', // Stateless chain
'/api/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter', // Stateless chain
'/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
]
grails.plugin.springsecurity.rest.login.active=true
grails.plugin.springsecurity.rest.login.endpointUrl='/api/login'
grails.plugin.springsecurity.rest.login.failureStatusCode=401
grails.plugin.springsecurity.rest.login.useJsonCredentials=true
grails.plugin.springsecurity.rest.login.usernamePropertyName='username'
grails.plugin.springsecurity.rest.login.passwordPropertyName='password'
grails.plugin.springsecurity.rest.logout.endpointUrl='/auth/logout'
grails.plugin.springsecurity.rest.token.generation.useSecureRandom=true
grails.plugin.springsecurity.rest.token.generation.useUUID=false
grails.plugin.springsecurity.rest.token.validation.active=true
grails.plugin.springsecurity.rest.token.validation.endpointUrl='/auth/validate'
Ps。我还尝试通过将 '/external/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
添加到数组
grails.plugin.springsecurity.filterChain.chainMap
网址映射:
group("/external") {
"/user/info" (controller: 'external', action: 'Service_UserInfo')
}
似乎问题是:您的 url http://localhost:7070/backend3/external/user/info
不在 /api/** 下,因此正在调用常规 spring 安全过滤器链而不是其余 api 个过滤器链。
尝试
/external/**: 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter'
同样默认使用不记名令牌。所以你必须在授权 header 中传递持有者令牌,除非你更改了 header 名称并禁用了持有者令牌。
我的老板设法让它为我工作。主要问题似乎是我试图访问的控制器。控制器现在看起来像这样:
// package statement
// import statements
import grails.rest.RestfulController
class UserController extends RestfulController<User> {
def springSecurityService
static responseFormats = ['json', 'xml']
UserController() {
super(User)
}
@Secured(['permitAll'])
def index() {
// use this method to test the api without authenticating
// if you are authenticated though, it'll let you know.
if(springSecurityService.isLoggedIn()) {
render(text:[loggedIn:'true'] as JSON)
} else {
render(text:[loggedIn:'false'] as JSON)
}
}
@Secured(['ROLE_USER'])
def listContacts() {
// needs authentication to access so if you call this method
// through the api and it returns users you're golden
def result = User.findAll()
respond result, [excludes: ['class']]
}
}
所以关键区别似乎是导入和扩展 RestfulController、responseFormats 和构造函数。我实际上并不知道这意味着什么或它是如何工作的,所以如果有人想编辑对此答案的解释,请拜访我。
我犯的另一个主要错误是在休息电话中。我会用我的 username/password 作为 json 参数调用 /api/login,这 return access_token
没问题。但是当我想访问时,例如,/user/listContacts,我会将 access_token
作为带有键 access_token
的参数发送,而不是将其作为带有键 header 的参数发送=15=]。这样做似乎是修复的一部分。
我的老板还删除了我的配置文件中的大部分废话(与 Spring 安全和休息相关),所以我也将提供这些更改。请注意,控制器、配置和 API 调用是唯一必要的更改,因此您项目中的所有其他内容都可以保持标准(除了在您的 BuildConfig 中包含插件)。
//Config for Spring Security REST plugin
//login
grails.plugin.springsecurity.rest.login.useJsonCredentials = true
grails.plugin.springsecurity.rest.token.storage.useGorm = true
grails.plugin.springsecurity.rest.token.storage.gorm.tokenDomainClassName = 'com.crastino.domain.AuthenticationToken'
就是这样。此外,here's 一个 link 的示例项目很有帮助。
就是这样。