面临拒绝访问(403) - 春季安全oauth2

时间:2017-07-16 06:48:05

标签: spring-boot spring-security spring-security-oauth2

.antMatchers("/secure2/**").authenticated();

我已将其中一个api配置为受保护,当我尝试访问它时,它给出了Access Denied错误消息,我不知道可能是什么原因。请注意,我正在传递有效的访问令牌。

我的方案: 基本上我已经在授权服务器中创建了logout rest api,我希望这样,带有有效令牌的请求可以命中这个api。

请求:

GET /auth/secure2 HTTP/1.1
Host: localhost:9191
Authorization: Bearer 33984141-1249-4465-a3aa-0b95a053fc63
Cache-Control: no-cache
Postman-Token: f4661790-a8e1-90ea-f6db-79cb37958cdf

响应:

{
    "timestamp": 1500186837033,
    "status": 403,
    "error": "Forbidden",
    "message": "Access Denied",
    "path": "/auth/secure2"
}

我发现下面的方法返回false,因为它引发了拒绝访问错误。

public final class ExpressionUtils {

    public static boolean evaluateAsBoolean(Expression expr, EvaluationContext ctx) {
        try {
            return ((Boolean) expr.getValue(ctx, Boolean.class)).booleanValue();
        }
        catch (EvaluationException e) {
            throw new IllegalArgumentException("Failed to evaluate expression '"
                    + expr.getExpressionString() + "'", e);
        }
    }
}

下面是我在框架中调试捕获的屏幕截图。另请查看评论中提到的图片。

Image1

代码:

SecurityConfiguration.java:

import org.springframework.beans.factory.annotation.Autowired;


@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new StandardPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
      throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider
          = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(encoder());
        return authProvider;
    }

    @Bean
    public ShaPasswordEncoder encoder() {
        return new ShaPasswordEncoder(256);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {}

    @Override
    protected void configure(HttpSecurity http) throws Exception {
         http
         .exceptionHandling()
         .accessDeniedHandler(accessDeniedHandler())
         .and()
         .csrf()
         .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
         .disable()
         .headers()
         .frameOptions().disable().disable()
         .sessionManagement()
         .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
         .and()
         .authorizeRequests()
         .antMatchers("/hello/").permitAll()
         .antMatchers("/secure3/").permitAll()
         .antMatchers("/oauth/token/revoke/**").authenticated()
         .antMatchers("/secure2/**").authenticated();

    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler(){
        return new CustomAccessDeniedHandler();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
    private static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {

        public GlobalSecurityConfiguration() {
        }
        @Override
        protected MethodSecurityExpressionHandler createExpressionHandler() {
            return new OAuth2MethodSecurityExpressionHandler();
        }

    }

}

Oauth2Configuration.java

@Configuration
public class OAuth2Configuration {


    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {

        private static final String ENV_OAUTH = "authentication.oauth.";
        //private static final String PROP_CLIENTID = "clientid";
        //private static final String PROP_SECRET = "secret";
        private static final String PROP_ACCESS_TOKEN_VALIDITY_SECONDS = "accessTokenValidityInSeconds";
        private static final String PROP_REFRESH_TOKEN_VALIDITY_SECONDS = "refreshTokenValidityInSeconds";

        private RelaxedPropertyResolver propertyResolver;

        @Autowired
        private DataSource dataSource;

        @Autowired
        private CustomUserDetailService userDetailsService;

        @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                throws Exception {
            endpoints.tokenStore(tokenStore())
                     .userDetailsService(userDetailsService)
                     .tokenEnhancer(tokenEnhancer())
                     .accessTokenConverter(accessTokenConverter())
                     .authenticationManager(authenticationManager);
        }

        @Bean
        public TokenEnhancer tokenEnhancer() {
           return new CustomTokenEnhancer();
        }

        @Bean
        public DefaultAccessTokenConverter accessTokenConverter() {
            return new DefaultAccessTokenConverter();
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer)
                throws Exception {
            oauthServer
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()");
        }


        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients
                    .inMemory()

                    .withClient("clientId")
                    .scopes("read", "write")
                    .authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
                    .authorizedGrantTypes("password", "refresh_token")
                    .accessTokenValiditySeconds(propertyResolver.getProperty(PROP_ACCESS_TOKEN_VALIDITY_SECONDS, Integer.class, 80))
                    .refreshTokenValiditySeconds(propertyResolver.getProperty(PROP_REFRESH_TOKEN_VALIDITY_SECONDS, Integer.class, 180))

                    .and().inMemory()
                    .withClient("clientid")
                    .scopes("read", "write")
                    .authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
                    .authorizedGrantTypes("client_credentials")
                    .secret("secret");

        }

        @Override
        public void setEnvironment(Environment environment) {
            this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
        }

    }

控制器:

@Controller
@RequestMapping("/secure2")
public class SecureController1 {

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public String sayHello() {

        return "Secure Hello secure2!";
    }

}

它引发访问被拒绝错误消息的场景是什么?如果需要任何其他信息,请告诉我。

1 个答案:

答案 0 :(得分:1)

我使用了这些代码,并且效果很好。

OAuth2AuthorizationServerConfig.java:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    // Configure the token store and authentication manager
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //@formatter:off
        endpoints
                .tokenStore(tokenStore())
                .accessTokenConverter(accessTokenConverter()) // added for JWT
                .authenticationManager(authenticationManager);
        //@formatter:on
    }

    // Configure a client store. In-memory for simplicity, but consider other
    // options for real apps.


    //It is not necessary.works even without this func:)
//    @Override
//    public void configure(AuthorizationServerSecurityConfigurer oauthServer)
//            throws Exception {
//        oauthServer
//                .tokenKeyAccess("permitAll()")
//                .checkTokenAccess("isAuthenticated()");
//    }


    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //@formatter:off
        clients
                .inMemory()
                .withClient("myclient")//username in basic auth header
                .secret ("{noop}123")//password in basic auth header;
                .authorizedGrantTypes("authorization_code", "implicit", "password", "client_credentials", "refresh_token")
                .scopes("read")
                //.redirectUris("http://localhost:9191/x")
                .accessTokenValiditySeconds(86400); // 24 hours
        //@formatter:on
    }

    // A token store bean. JWT token store
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter()); // For JWT. Use in-memory, jdbc, or other if not JWT
    }

    // Token converter. Needed for JWT
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("123"); // symmetric key
        return converter;
    }

    // Token services. Needed for JWT
    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }


//    @Bean
//
//    public PasswordEncoder passwordEncoder () {
//
//        return new BCryptPasswordEncoder();
//
//    }
}

WebSecurityConfig:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;


    //It is not important to use this func. /oauth/token is the default path of spring security to use oauth2. she is so clever!! :)
//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//
//
//        http.authorizeRequests()
//                .antMatchers(HttpMethod.POST, "/oauth/token").permitAll()
//                .anyRequest().authenticated();
//    }

    @Autowired
    public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("{noop}user").roles("ROLE");
    }

//
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.userDetailsService(userDetailsService)
//                .passwordEncoder(passwordEncoder());
//    }


    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

//
//    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
//    }
}

输出: 请注意,代码和邮递员中使用的用户名和密码的值必须相同。

enter image description here enter image description here

希望对您有所帮助:)