• 排查spring boot security oauth2使用check-token-access做token检查后,resourceId检查失效


    最近在项目中,使用check-token-access检查token有效性,配合security.oauth2.resource.user-info-uri来获取用户信息。

    在使用这个配置后,resourceId校验就失效了,于是跟了源码,发现在类OAuth2AuthenticationManager的以下方法做的resouceId校验:

    OAuth2Authentication auth = tokenServices.loadAuthentication(token);

     这行代码是获取当前用户的登录信息的,跟进后,是UserInfoTokenServices类里做了数据转换,在以下代码中,丢失了登录信息中保存的resourceId数据:

    改进方案:

    继承类UserInfoTokenServices,重写相关方法解决此问题:

    public class CustomUserInfoTokenServices extends UserInfoTokenServices {
        private String tokenType = "Bearer";
        private final String clientId;
        private final AuthoritiesExtractor authoritiesExtractor = new FixedAuthoritiesExtractor();
        private final String userInfoEndpointUrl;
        private OAuth2RestOperations restTemplate;
    
        public CustomUserInfoTokenServices(String userInfoEndpointUrl, String clientId) {
            super(userInfoEndpointUrl, clientId);
            this.clientId = clientId;
            this.userInfoEndpointUrl = userInfoEndpointUrl;
        }
    
        @Override
        public void setTokenType(String tokenType) {
            this.tokenType = tokenType;
            super.setTokenType(tokenType);
        }
    
        @Override
        public void setRestTemplate(OAuth2RestOperations restTemplate) {
            super.setRestTemplate(restTemplate);
            this.restTemplate = restTemplate;
        }
    
        
    
        @Override
        public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {
            Map<String, Object> map = this.getMap(this.userInfoEndpointUrl, accessToken);
            if (map.containsKey("error")) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("userinfo returned error: " + map.get("error"));
                }
    
                throw new InvalidTokenException(accessToken);
            } else {
                return this.extractAuthentication(map);
            }
        }
    
        private OAuth2Authentication extractAuthentication(Map<String, Object> map) {
            Object principal = this.getPrincipal(map);
            List<GrantedAuthority> authorities = this.authoritiesExtractor.extractAuthorities(map);
    
            Map<String, Object> oauth2Request = (Map<String, Object>) map.get("oauth2Request");
            ArrayList<String> resourceIds = (ArrayList<String>) oauth2Request.get("resourceIds");
            Set<String> resourceIdsSet = new HashSet<>(resourceIds.size());
            resourceIdsSet.addAll(resourceIds);
    
            OAuth2Request request = new OAuth2Request(null, this.clientId, null, true, null, resourceIdsSet, null, null, null);
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(principal, "N/A", authorities);
            token.setDetails(map);
            return new OAuth2Authentication(request, token);
        }
    
        private Map<String, Object> getMap(String path, String accessToken) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Getting user info from: " + path);
            }
    
            try {
                OAuth2RestOperations restTemplate = this.restTemplate;
                if (restTemplate == null) {
                    BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
                    resource.setClientId(this.clientId);
                    restTemplate = new OAuth2RestTemplate(resource);
                }
    
                OAuth2AccessToken existingToken = restTemplate.getOAuth2ClientContext().getAccessToken();
                if (existingToken == null || !accessToken.equals(existingToken.getValue())) {
                    DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(accessToken);
                    token.setTokenType(this.tokenType);
                    restTemplate.getOAuth2ClientContext().setAccessToken(token);
                }
    
                return (Map<String, Object>) restTemplate.getForEntity(path, Map.class, new Object[0]).getBody();
            } catch (Exception var6) {
                this.logger.warn("Could not fetch user details: " + var6.getClass() + ", " + var6.getMessage());
                return Collections.singletonMap("error", "Could not fetch user details");
            }
        }

    然后在配置中,设置该实现类:

    Configuration
    @EnableResourceServer
    public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
        @Resource
        private ResourceServerProperties properties;
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
                    .antMatchers(
                            "/v2/api-docs/**",
                            "/swagger-resources/**",
                            "/swagger-ui.html",
                            "/webjars/**",
                            ,"/favicon.ico"
                    ).permitAll()
                    .anyRequest().authenticated()
                    /* .and()
                    //统一自定义异常
                     .exceptionHandling()
                    .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                    .accessDeniedHandler(new CustomAccessDeniedHandler())*/
                    .and()
                    .csrf().disable();
        }
    
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(properties.getResourceId());
            resources.tokenServices(customUserInfoTokenServices());
        }
    
    
        @Bean
        public CustomUserInfoTokenServices customUserInfoTokenServices() {
            return new CustomUserInfoTokenServices(properties.getUserInfoUri(), properties.getClientId());
        }
  • 相关阅读:
    20135202闫佳歆-第二章家庭作业-2.69
    20135202闫佳歆——信息安全系统设计基础第六周学习总结
    20135202闫佳歆——信息安全系统设计基础第五周学习总结
    20135202闫佳歆——信息安全系统设计基础第四周学习总结
    20135202闫佳歆-信息安全系统设计基础第三周学习总结
    20135202闫佳歆——信息安全系统设计基础第二周学习总结
    php txt操作
    phpexcel 导入导出
    windows mysqldump 不成功 1049 1064 报错
    钉钉 移动端免登录 dd.ready不运行或者一直运行
  • 原文地址:https://www.cnblogs.com/chongsha/p/14504169.html
Copyright © 2020-2023  润新知