Grails 2.5.4 / Spring Security Rest 1.5.4 - 验证令牌

时间:2017-08-03 18:50:54

标签: grails spring-security spring-security-rest

我要做的是登录用户并获取令牌(此部分有效)。然后我想在每次访问API路径时验证此令牌。我显然做错了,也许我不完全理解Spring Security Rest插件实际上应该做什么,但每当我调用API路径并发送令牌时,我得到的就是Spring Security登录页面的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 Security规则下的配置中,我有'/external/**':['ROLE_USER']。如果我将其更改为['permitAll'],那么我获得访问没有问题,但是弹簧安全性实际上是无用的。

API请求(路径:http://localhost:7070/backend3/external/user/info

{
    "access_token": "eyJhbGciOiJIU" // shortened token to conserve space
}

然后返回标准登录页面的html。我尝试过发送access_tokenusernametoken_typeroles之类的各种组合。我甚至尝试了access_token的不同格式;我在docs找到的"Authorization":"Bearer eyJhbGciOiJIU"但没有任何作用。

有人可以向我解释如何解决这个问题,因为文档假设了很多我以前没有的先验知识。我将在下面发布我的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'

聚苯乙烯。我还尝试通过将grails.plugin.springsecurity.filterChain.chainMap添加到数组的末尾来添加我尝试访问此部分'/external/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'的路径

UrlMappings:

group("/external") {
    "/user/info" (controller: 'external', action: 'Service_UserInfo')
}

2 个答案:

答案 0 :(得分:0)

似乎问题是:您的网址http://localhost:7070/backend3/external/user/info不在/ api / **下,因此正在调用常规spring安全过滤器链而不是其余的api过滤器链。

尝试

/external/**: 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter'

此外,默认情况下使用承载令牌。因此,您必须在授权标头中传递承载令牌,除非您更改了标头名称并禁用了承载令牌。

答案 1 :(得分:0)

我的老板设法让它为我工作。主要问题似乎是我试图访问的控制器。控制器现在看起来像这样:

// 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和构造函数。我实际上并不知道这意味着什么或它是如何工作的,所以如果有人想编辑这个答案的解释是我的客人。

我犯的另一个关键错误是在休息电话中。我会使用我的用户名/密码调用/ api / login作为json参数,这将返回access_token没问题。但是当我想访问时,例如/ user / listContacts,我会将access_token作为带有密钥access_token的参数发送,而不是将其作为带有密钥X-Auth-Token的标头发送。这样做似乎是解决方案的一部分。

我的老板还删除了我的配置文件中的大部分废话(与Spring Security和Rest相关),所以我也只是提供这些更改。请注意,控制器,配置和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指向一个帮助很多的示例项目的链接。

就是这样。