美文网首页Oauth2
聊聊spring security oauth2的几个endpo

聊聊spring security oauth2的几个endpo

作者: go4it | 来源:发表于2017-12-12 09:20 被阅读184次

    本文就来讲一下spring security oauth2的几个endpoint的认证

    endpoint

    spring-security-oauth2-2.0.14.RELEASE-sources.jar!/org/springframework/security/oauth2/config/annotation/web/configuration/AuthorizationServerEndpointsConfiguration.java

    @Configuration
    @Import(TokenKeyEndpointRegistrar.class)
    public class AuthorizationServerEndpointsConfiguration {
    
        private AuthorizationServerEndpointsConfigurer endpoints = new AuthorizationServerEndpointsConfigurer();
    
        @Autowired
        private ClientDetailsService clientDetailsService;
    
        @Autowired
        private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();
    
        @PostConstruct
        public void init() {
            for (AuthorizationServerConfigurer configurer : configurers) {
                try {
                    configurer.configure(endpoints);
                } catch (Exception e) {
                    throw new IllegalStateException("Cannot configure enpdoints", e);
                }
            }
            endpoints.setClientDetailsService(clientDetailsService);
        }
    
        @Bean
        public AuthorizationEndpoint authorizationEndpoint() throws Exception {
            AuthorizationEndpoint authorizationEndpoint = new AuthorizationEndpoint();
            FrameworkEndpointHandlerMapping mapping = getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
            authorizationEndpoint.setUserApprovalPage(extractPath(mapping, "/oauth/confirm_access"));
            authorizationEndpoint.setProviderExceptionHandler(exceptionTranslator());
            authorizationEndpoint.setErrorPage(extractPath(mapping, "/oauth/error"));
            authorizationEndpoint.setTokenGranter(tokenGranter());
            authorizationEndpoint.setClientDetailsService(clientDetailsService);
            authorizationEndpoint.setAuthorizationCodeServices(authorizationCodeServices());
            authorizationEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
            authorizationEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
            authorizationEndpoint.setUserApprovalHandler(userApprovalHandler());
            return authorizationEndpoint;
        }
    
        @Bean
        public TokenEndpoint tokenEndpoint() throws Exception {
            TokenEndpoint tokenEndpoint = new TokenEndpoint();
            tokenEndpoint.setClientDetailsService(clientDetailsService);
            tokenEndpoint.setProviderExceptionHandler(exceptionTranslator());
            tokenEndpoint.setTokenGranter(tokenGranter());
            tokenEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
            tokenEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
            tokenEndpoint.setAllowedRequestMethods(allowedTokenEndpointRequestMethods());
            return tokenEndpoint;
        }
    
        @Bean
        public CheckTokenEndpoint checkTokenEndpoint() {
            CheckTokenEndpoint endpoint = new CheckTokenEndpoint(getEndpointsConfigurer().getResourceServerTokenServices());
            endpoint.setAccessTokenConverter(getEndpointsConfigurer().getAccessTokenConverter());
            endpoint.setExceptionTranslator(exceptionTranslator());
            return endpoint;
        }
    
        @Bean
        public WhitelabelApprovalEndpoint whitelabelApprovalEndpoint() {
            return new WhitelabelApprovalEndpoint();
        }
    
        @Bean
        public WhitelabelErrorEndpoint whitelabelErrorEndpoint() {
            return new WhitelabelErrorEndpoint();
        }
    
        //......
    }
    

    这里显示配置了如下几个

    • /oauth/authorize
    • /oauth/token
    • /oauth/check_token
    • /oauth/confirm_access
    • /oauth/error

    endpoint的认证

    /oauth/authorize

    这个需要保护用户账号密码认证保护,否则会报

    curl -i http://localhost:8080/oauth/authorize\?response_type\=code\&client_id\=demoApp\&redirect_uri\=http://localhost:8081/callback
    HTTP/1.1 500
    X-Application-Context: application
    Content-Type: application/json;charset=UTF-8
    Transfer-Encoding: chunked
    Date: Sun, 10 Dec 2017 07:12:50 GMT
    Connection: close
    
    {"timestamp":1512889970484,"status":500,"error":"Internal Server Error","exception":"org.springframework.security.authentication.InsufficientAuthenticationException","message":"User must be authenticated with Spring Security before authorization can be completed.","path":"/oauth/authorize"}
    

    /oauth/token

    • 这个如果配置支持allowFormAuthenticationForClients的,且url中有client_id和client_secret的会走ClientCredentialsTokenEndpointFilter来保护
    • 如果没有支持allowFormAuthenticationForClients或者有支持但是url中没有client_id和client_secret的,走basic认证保护

    /oauth/check_token

    这个走basic认证保护

    /oauth/confirm_access

    这个需要认证保护,否则报500

    curl -i http://localhost:8080/oauth/confirm_access
    
    HTTP/1.1 500
    X-Application-Context: application
    Cache-Control: no-store
    Content-Type: application/json;charset=UTF-8
    Content-Language: zh-CN
    Transfer-Encoding: chunked
    Date: Sun, 10 Dec 2017 07:13:55 GMT
    Connection: close
    
    {"timestamp":1512890035907,"status":500,"error":"Internal Server Error","exception":"org.springframework.expression.spel.SpelEvaluationException","message":"EL1008E: Property or field 'authorizationRequest' cannot be found on object of type 'java.util.HashMap' - maybe not public?","path":"/oauth/confirm_access"}
    

    /oauth/error

    这个可以不用认证保护

    basic认证保护的源码

    spring-security-oauth2-2.0.14.RELEASE-sources.jar!/org/springframework/security/oauth2/config/annotation/web/configuration/AuthorizationServerSecurityConfiguration.java

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            AuthorizationServerSecurityConfigurer configurer = new AuthorizationServerSecurityConfigurer();
            FrameworkEndpointHandlerMapping handlerMapping = endpoints.oauth2EndpointHandlerMapping();
            http.setSharedObject(FrameworkEndpointHandlerMapping.class, handlerMapping);
            configure(configurer);
            http.apply(configurer);
            String tokenEndpointPath = handlerMapping.getServletPath("/oauth/token");
            String tokenKeyPath = handlerMapping.getServletPath("/oauth/token_key");
            String checkTokenPath = handlerMapping.getServletPath("/oauth/check_token");
            if (!endpoints.getEndpointsConfigurer().isUserDetailsServiceOverride()) {
                UserDetailsService userDetailsService = http.getSharedObject(UserDetailsService.class);
                endpoints.getEndpointsConfigurer().userDetailsService(userDetailsService);
            }
            // @formatter:off
            http
                .authorizeRequests()
                    .antMatchers(tokenEndpointPath).fullyAuthenticated()
                    .antMatchers(tokenKeyPath).access(configurer.getTokenKeyAccess())
                    .antMatchers(checkTokenPath).access(configurer.getCheckTokenAccess())
            .and()
                .requestMatchers()
                    .antMatchers(tokenEndpointPath, tokenKeyPath, checkTokenPath)
            .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
            // @formatter:on
            http.setSharedObject(ClientDetailsService.class, clientDetailsService);
        }
    

    其中,可以自己指定check_token的认证级别,而/oauth/token则需要fullyAuthenticated

    token_key这个是jwt特有的,这里忽略不讲

    isAuthenticated()与isFullyAuthenticated的区别

    一个是authenticated,一个是fullyAuthenticated,前者排除anonymous,后者排除anonymous以及remember-me

    • isAuthenticated()

    Returns true if the user is not anonymous

    • isFullyAuthenticated()

    Returns true if the user is not an anonymous or a remember-me user

    小结

    综上,需要保护/oauth/authorize以及/oauth/confirm_access这两个endpoint,当然主要是/oauth/authorize这个。

    由于其他几个/oauth/开头的认证endpoint配置的认证优先级高于默认的WebSecurityConfigurerAdapter配置(order=100),因此默认的可以这样配置

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
            http
                    .requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**")
                    .and()
                    .authorizeRequests()
                    .antMatchers("/oauth/**").authenticated()
                    .and()
                    .formLogin().permitAll(); //新增login form支持用户登录及授权
        }
    }
    

    把整个/oauth/**保护进来

    doc

    相关文章

      网友评论

        本文标题:聊聊spring security oauth2的几个endpo

        本文链接:https://www.haomeiwen.com/subject/gjjgixtx.html