3

は私が達成しようとしていることである:Springブートアプリケーションでベアラ認証を有効にするには?

JDBC
  • APIを介してアクセスされるデータベース(つまりMySQLの)に保存されている
  • ユーザー、当局、クライアントとアクセストークンは、私が持つことができる」依頼するあなたのためのエンドポイントを公開し
      OAuth2ベアラ私はクライアントのIDを知っている秘密の」
    • APIは、あなたがあなたのリクエストヘッダに

    をベアラトークンを供給する場合、私はこれでかなり遠くなったMVCのエンドポイントにアクセスすることができますトークン - 最初の2点が働いていることは? 。

    標準のテーブル名がすでに私のデータベースで使用されているため(私は、例えば "users"テーブルがすでにあります)、私のSpring Bootアプリケーションに完全にデフォルトのOAuth2セットアップを使用することができませんでした。

    JdbcTokenStore、JdbcClientDetailsS​​ervice、およびJdbcAuthorizationCodeServicesのインスタンスを手動で構築し、データベースからカスタムテーブル名を使用し、これらのインスタンスを使用するようにアプリケーションを設定するように設定しました。


    ここまではこれまでのことです。ベアラトークンを求めることができます:

    # The `-u` switch provides the client ID & secret over HTTP Basic Auth 
    curl -u8fc9d384-619a-11e7-9fe6-246798c61721:9397ce6c-619a-11e7-9fe6-246798c61721 \ 
    'http://localhost:8080/oauth/token' \ 
    -d grant_type=password \ 
    -d username=bob \ 
    -d password=tom 
    

    私は応答を受け取ります。いいよ!

    {"access_token":"1ee9b381-e71a-4e2f-8782-54ab1ce4d140","token_type":"bearer","refresh_token":"8db897c7-03c6-4fc3-bf13-8b0296b41776","expires_in":26321,"scope":"read write"} 
    

    今、私はトークン使用にしてみてください:

    curl 'http://localhost:8080/test' \ 
    -H "Authorization: Bearer 1ee9b381-e71a-4e2f-8782-54ab1ce4d140" 
    

    可哀想:

    { 
        "timestamp":1499452163373, 
        "status":401, 
        "error":"Unauthorized", 
        "message":"Full authentication is required to access this resource", 
        "path":"/test" 
    } 
    

    この手段(この特定のケースでは)それが戻っ匿名に下落していること認証。これは、10〜フィルタを明らかに

    logging.level: 
        org.springframework: 
         security: DEBUG 
    

    :私は、ロギングの冗長性を増やすことで、これをより深く調査し

    { 
        "timestamp":1499452555312, 
        "status":401, 
        "error":"Unauthorized", 
        "message":"An Authentication object was not found in the SecurityContext", 
        "path":"/test" 
    } 
    

    :私は私のHttpSecurityに.anonymous().disable()を追加する場合は、本当エラーを見ることができます私の要求が旅行する:

    o.s.security.web.FilterChainProxy  : /test at position 1 of 10 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 
    o.s.security.web.FilterChainProxy  : /test at position 2 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 
    w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists 
    w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created. 
    o.s.security.web.FilterChainProxy  : /test at position 3 of 10 in additional filter chain; firing Filter: 'HeaderWriterFilter' 
    o.s.security.web.FilterChainProxy  : /test at position 4 of 10 in additional filter chain; firing Filter: 'LogoutFilter' 
    o.s.security.web.FilterChainProxy  : /test at position 5 of 10 in additional filter chain; firing Filter: 'BasicAuthenticationFilter' 
    o.s.security.web.FilterChainProxy  : /test at position 6 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' 
    o.s.security.web.FilterChainProxy  : /test at position 7 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 
    o.s.security.web.FilterChainProxy  : /test at position 8 of 10 in additional filter chain; firing Filter: 'SessionManagementFilter' 
    o.s.security.web.FilterChainProxy  : /test at position 9 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 
    o.s.security.web.FilterChainProxy  : /test at position 10 of 10 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 
    o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /test; Attributes: [authenticated] 
    o.s.s.w.a.ExceptionTranslationFilter  : Authentication exception occurred; redirecting to authentication entry point 
    
    org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext 
        at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:379) ~[spring-security-core-4.2.3.RELEASE.jar:4.2.3.RELEASE] 
    

    匿名ユーザーがを無効にした場合の表示は、です。彼らはを有効にしている場合:AnonymousAuthenticationFilterちょうどSecurityContextHolderAwareRequestFilter後にフィルター・チェーンに加え、シーケンスはより次のように終了さ:

    o.s.security.web.FilterChainProxy  : /test at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 
    o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /test; Attributes: [authenticated] 
    o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.sprin[email protected]9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS 
    o.s.s.access.vote.AffirmativeBased  : Voter: org.sp[email protected]5ff24abf, returned: -1 
    o.s.s.w.a.ExceptionTranslationFilter  : Access is denied (user is anonymous); redirecting to authentication entry point 
    
    org.springframework.security.access.AccessDeniedException: Access is denied 
        at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-4.2.3.RELEASE.jar:4.2.3.RELEASE] 
    

    いずれかの方法:いいえ良いです。

    本質的に、私たちはフィルターチェーンの中にあるステップを欠いていることを私に示しています。私たちは、セキュリティコンテキストの認証を取り込むのServletRequestのヘッダを読んでいましたフィルターを必要とする:

    SecurityContextHolder.getContext().setAuthentication(request: HttpServletRequest); 
    

    が、私はこのようなフィルタを取得する方法だろうか?


    これは私のアプリケーションの外観です。それはKotlinですが、Javaの目にはうまくいくはずです。

    Application.kt:

    @SpringBootApplication(scanBasePackageClasses=arrayOf(
         com.example.domain.Package::class, 
         com.example.service.Package::class, 
         com.example.web.Package::class 
    )) 
    class MyApplication 
    
    fun main(args: Array<String>) { 
        SpringApplication.run(MyApplication::class.java, *args) 
    } 
    

    TestController:

    @RestController 
    class TestController { 
        @RequestMapping("/test") 
        fun Test(): String { 
         return "hey there" 
        } 
    } 
    

    MyWebSecurityConfigurerAdapter:

    @Configuration 
    @EnableWebSecurity 
    /** 
    * Based on: 
    * https://stackoverflow.com/questions/25383286/spring-security-custom-userdetailsservice-and-custom-user-class 
    * 
    * Password encoder: 
    * http://www.baeldung.com/spring-security-authentication-with-a-database 
    */ 
    class MyWebSecurityConfigurerAdapter(
         val userDetailsService: MyUserDetailsService 
    ) : WebSecurityConfigurerAdapter() { 
    
        private val passwordEncoder = BCryptPasswordEncoder() 
    
        override fun userDetailsService() : UserDetailsService { 
         return userDetailsService 
        } 
    
        override fun configure(auth: AuthenticationManagerBuilder) { 
         auth 
           .authenticationProvider(authenticationProvider()) 
        } 
    
        @Bean 
        fun authenticationProvider() : AuthenticationProvider { 
         val authProvider = DaoAuthenticationProvider() 
         authProvider.setUserDetailsService(userDetailsService()) 
         authProvider.setPasswordEncoder(passwordEncoder) 
         return authProvider 
        } 
    
        override fun configure(http: HttpSecurity?) { 
         http!! 
           .anonymous().disable() 
           .authenticationProvider(authenticationProvider()) 
           .authorizeRequests() 
            .anyRequest().authenticated() 
           .and() 
           .httpBasic() 
           .and() 
           .csrf().disable() 
        } 
    } 
    

    MyAuthorizationServerConfigurerAdapter:

    /** 
    * Based on: 
    * https://github.com/spring-projects/spring-security-oauth/blob/master/tests/annotation/jdbc/src/main/java/demo/Application.java#L68 
    */ 
    @Configuration 
    @EnableAuthorizationServer 
    class MyAuthorizationServerConfigurerAdapter(
         val auth : AuthenticationManager, 
         val dataSource: DataSource, 
         val userDetailsService: UserDetailsService 
    
    ) : AuthorizationServerConfigurerAdapter() { 
    
        private val passwordEncoder = BCryptPasswordEncoder() 
    
        @Bean 
        fun tokenStore(): JdbcTokenStore { 
         val tokenStore = JdbcTokenStore(dataSource) 
         val oauthAccessTokenTable = "auth_schema.oauth_access_token" 
         val oauthRefreshTokenTable = "auth_schema.oauth_refresh_token" 
         tokenStore.setDeleteAccessTokenFromRefreshTokenSql("delete from ${oauthAccessTokenTable} where refresh_token = ?") 
         tokenStore.setDeleteAccessTokenSql("delete from ${oauthAccessTokenTable} where token_id = ?") 
         tokenStore.setDeleteRefreshTokenSql("delete from ${oauthRefreshTokenTable} where token_id = ?") 
         tokenStore.setInsertAccessTokenSql("insert into ${oauthAccessTokenTable} (token_id, token, authentication_id, " + 
           "user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)") 
         tokenStore.setInsertRefreshTokenSql("insert into ${oauthRefreshTokenTable} (token_id, token, authentication) values (?, ?, ?)") 
         tokenStore.setSelectAccessTokenAuthenticationSql("select token_id, authentication from ${oauthAccessTokenTable} where token_id = ?") 
         tokenStore.setSelectAccessTokenFromAuthenticationSql("select token_id, token from ${oauthAccessTokenTable} where authentication_id = ?") 
         tokenStore.setSelectAccessTokenSql("select token_id, token from ${oauthAccessTokenTable} where token_id = ?") 
         tokenStore.setSelectAccessTokensFromClientIdSql("select token_id, token from ${oauthAccessTokenTable} where client_id = ?") 
         tokenStore.setSelectAccessTokensFromUserNameAndClientIdSql("select token_id, token from ${oauthAccessTokenTable} where user_name = ? and client_id = ?") 
         tokenStore.setSelectAccessTokensFromUserNameSql("select token_id, token from ${oauthAccessTokenTable} where user_name = ?") 
         tokenStore.setSelectRefreshTokenAuthenticationSql("select token_id, authentication from ${oauthRefreshTokenTable} where token_id = ?") 
         tokenStore.setSelectRefreshTokenSql("select token_id, token from ${oauthRefreshTokenTable} where token_id = ?") 
         return tokenStore 
        } 
    
        override fun configure(security: AuthorizationServerSecurityConfigurer?) { 
         security!!.passwordEncoder(passwordEncoder) 
        } 
    
        override fun configure(clients: ClientDetailsServiceConfigurer?) { 
         val clientDetailsService = JdbcClientDetailsService(dataSource) 
         clientDetailsService.setPasswordEncoder(passwordEncoder) 
    
         val clientDetailsTable = "auth_schema.oauth_client_details" 
         val CLIENT_FIELDS_FOR_UPDATE = "resource_ids, scope, " + 
           "authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, " + 
           "refresh_token_validity, additional_information, autoapprove" 
         val CLIENT_FIELDS = "client_secret, ${CLIENT_FIELDS_FOR_UPDATE}" 
         val BASE_FIND_STATEMENT = "select client_id, ${CLIENT_FIELDS} from ${clientDetailsTable}" 
    
         clientDetailsService.setFindClientDetailsSql("${BASE_FIND_STATEMENT} order by client_id") 
         clientDetailsService.setDeleteClientDetailsSql("delete from ${clientDetailsTable} where client_id = ?") 
         clientDetailsService.setInsertClientDetailsSql("insert into ${clientDetailsTable} (${CLIENT_FIELDS}," + 
           " client_id) values (?,?,?,?,?,?,?,?,?,?,?)") 
         clientDetailsService.setSelectClientDetailsSql("${BASE_FIND_STATEMENT} where client_id = ?") 
         clientDetailsService.setUpdateClientDetailsSql("update ${clientDetailsTable} set " + 
           "${CLIENT_FIELDS_FOR_UPDATE.replace(", ", "=?, ")}=? where client_id = ?") 
         clientDetailsService.setUpdateClientSecretSql("update ${clientDetailsTable} set client_secret = ? where client_id = ?") 
         clients!!.withClientDetails(clientDetailsService) 
        } 
    
        override fun configure(endpoints: AuthorizationServerEndpointsConfigurer?) { 
         endpoints!! 
           .authorizationCodeServices(authorizationCodeServices()) 
           .authenticationManager(auth) 
           .tokenStore(tokenStore()) 
           .approvalStoreDisabled() 
           .userDetailsService(userDetailsService) 
        } 
    
        @Bean 
        protected fun authorizationCodeServices() : AuthorizationCodeServices { 
         val codeServices = JdbcAuthorizationCodeServices(dataSource) 
         val oauthCodeTable = "auth_schema.oauth_code" 
         codeServices.setSelectAuthenticationSql("select code, authentication from ${oauthCodeTable} where code = ?") 
         codeServices.setInsertAuthenticationSql("insert into ${oauthCodeTable} (code, authentication) values (?, ?)") 
         codeServices.setDeleteAuthenticationSql("delete from ${oauthCodeTable} where code = ?") 
         return codeServices 
        } 
    } 
    

    MyAuthorizationServerConfigurerAdapter:

    @Service 
    class MyUserDetailsService(
         val theDataSource: DataSource 
    ) : JdbcUserDetailsManager() { 
        @PostConstruct 
        fun init() { 
         dataSource = theDataSource 
    
         val usersTable = "auth_schema.users" 
         val authoritiesTable = "auth_schema.authorities" 
    
         setChangePasswordSql("update ${usersTable} set password = ? where username = ?") 
         setCreateAuthoritySql("insert into ${authoritiesTable} (username, authority) values (?,?)") 
         setCreateUserSql("insert into ${usersTable} (username, password, enabled) values (?,?,?)") 
         setDeleteUserAuthoritiesSql("delete from ${authoritiesTable} where username = ?") 
         setDeleteUserSql("delete from ${usersTable} where username = ?") 
         setUpdateUserSql("update ${usersTable} set password = ?, enabled = ? where username = ?") 
         setUserExistsSql("select username from ${usersTable} where username = ?") 
    
         setAuthoritiesByUsernameQuery("select username,authority from ${authoritiesTable} where username = ?") 
         setUsersByUsernameQuery("select username,password,enabled from ${usersTable} " + "where username = ?") 
        } 
    } 
    

    任意のアイデア? 私はどういうわけかOAuth2AuthenticationProcessingFilterを私のフィルターチェーンにインストールする必要がありますか?

    起動時にこのようなメッセージが表示されるのですが、問題に関連する可能性がありますか?

    u.c.c.h.s.auth.MyUserDetailsService  : No authentication manager set. Reauthentication of users when changing passwords will not be performed. 
    s.c.a.w.c.WebSecurityConfigurerAdapter$3 : No authenticationProviders and no parentAuthenticationManager defined. Returning null. 
    

    EDIT:

    OAuth2AuthenticationProcessingFilterをインストールするResourceServerConfigurerAdapterの仕事であるように見えます。

    MyResourceServerConfigurerAdapter:私は、次のクラスを追加している

    @Configuration 
    @EnableResourceServer 
    class MyResourceServerConfigurerAdapter : ResourceServerConfigurerAdapter() 
    

    をそして私は、これはそれがOAuth2AuthenticationProcessingFilterをインストールしようとするよう見ていそのconfigure(http: HttpSecurity)方法を、入力するResourceServerSecurityConfigurerの原因デバッガで確認しますフィルターチェーンに挿入します。

    しかし、それは成功したようには見えません。 Spring Securityのデバッグ出力によれば、私はまだフィルタチェーン内に同じ数のフィルタを持っています。 OAuth2AuthenticationProcessingFilterはそこにありません。どうしたの?


    EDIT2:問題はHttpSecurityを設定しようとしている私は2つのクラス(WebSecurityConfigurerAdapterResourceServerConfigurerAdapter)を持っているということであるのだろうか。それは相互に排他的ですか?

  • +0

    https://auth0.com/blog/securing-spring-boot-with-jwts/このリンクはあなたに役立ちます – Akash

    答えて

    1

    はい!この問題は、WebSecurityConfigurerAdapterResourceServerConfigurerAdapterの両方を登録したという事実に関連していました。

    解決方法:WebSecurityConfigurerAdapterを削除してください。

    @Configuration 
    @EnableResourceServer 
    class MyResourceServerConfigurerAdapter(
         val userDetailsService: MyUserDetailsService 
    ) : ResourceServerConfigurerAdapter() { 
        private val passwordEncoder = BCryptPasswordEncoder() 
    
        override fun configure(http: HttpSecurity?) { 
         http!! 
           .authenticationProvider(authenticationProvider()) 
           .authorizeRequests() 
           .anyRequest().authenticated() 
           .and() 
           .httpBasic() 
           .and() 
           .csrf().disable() 
        } 
    
        @Bean 
        fun authenticationProvider() : AuthenticationProvider { 
         val authProvider = DaoAuthenticationProvider() 
         authProvider.setUserDetailsService(userDetailsService) 
         authProvider.setPasswordEncoder(passwordEncoder) 
         return authProvider 
        } 
    } 
    

    EDIT::そして、このResourceServerConfigurerAdapterを使用するベアラ認証が(たとえば春アクチュエータによってインストールさ/metricsエンドポイント用)にすべてのエンドポイントを適用するために取得するためには、私は私が持っていたことが分かりました私のapplication.ymlsecurity.oauth2.resource.filter-order: 3を追加してください。 this answerを参照してください。

    関連する問題