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

Posted

技术标签:

【中文标题】Grails 2.5.4 / Spring Security Rest 1.5.4 - 验证令牌【英文标题】:Grails 2.5.4 / Spring Security Rest 1.5.4 - Validating token 【发布时间】:2018-01-11 12:54:20 【问题描述】:

我要做的是登录用户并取回令牌(这部分有效)。然后我想在每次访问 API 路径时验证这个令牌。我显然做错了什么,也许我不完全理解 Spring Security Rest 插件实际上应该做什么,但每当我调用 API 路径并发送令牌时,我得到的只是 Spring Security 登录页面的 html。我正在使用 Boomerang Soap 和 Rest 客户端。这是我要发送的内容。

登录请求(路径: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'

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

网址映射:

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

【问题讨论】:

尝试将 URL 映射更改为 group("/api/external") 并以 http://localhost:7070/backend3/api/external/user/info 访问资源 【参考方案1】:

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

试试

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

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

【讨论】:

感谢您的回复。我在filterChain.chainMap 中包含了上述内容(您忘记将冒号的左侧放在引号中)。现在我仍将"Authorization":"Bearer eyJhbGciOiJIU"(仍缩短)发送到相同的 URL,并且我仍在返回登录页面。我现在做错了什么? 默认情况下,插件会生成 JWT 令牌。请注意,使用 JWT 时,您不能插入任何其他令牌生成器。像 uuid 或安全随机。也尝试把 grails.plugin.springsecurity.rest.active = true 当您只访问 /api/xxx 而不传递令牌时,您会得到什么响应?你有登录页面吗?返回的登录页面表明未应用其余过滤器链。【参考方案2】:

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

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

我犯的另一个关键错误是在 rest 调用中。我会使用我的用户名/密码作为 json 参数调用 /api/login,这将返回 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 是一个帮助很大的示例项目的链接。

就是这样。

【讨论】:

以上是关于Grails 2.5.4 / Spring Security Rest 1.5.4 - 验证令牌的主要内容,如果未能解决你的问题,请参考以下文章

Grails Spring Security 验证多个 url 的访问

Grails 使用 spring-security-core-3.0.6+ 重定向注销后

在 grails gsp 中调用标签不起作用

grails spring-security 插件保护所有控制器,而不仅仅是带有@Secured注解的控制器

Grails - grails-spring-security-rest - 无法从 application.yml 加载 jwt 机密

Grails - 卸载 Spring Security Core