oauth2 通过SecurityContextHolder获取用户信息(二)

既上一篇获取用户信息,又找到了另一种获取用户信息的方法,在这做下介绍
本方法获取用户信息使用的是 token-info-uri
user-info-uri方式移步

资源服务配置文件

当使用token-info-uri时,默认user-info-uri不生效,loadBalanced:集群配置

security:
  oauth2:
    resource:
      loadBalanced: true
      user-info-uri: http://service-auth1/users/current
      token-info-uri: http://service-auth/oauth/check_token
    client:
      client-secret: 123456
      access-token-uri: http://service-auth/oauth/token
      grant-type: password,client_credentials,refresh_token,authorization_code
      scope: all
      client-id: client

资源服务器配置

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    /**
     * 资源服务器配置
     */
    @Resource
    private ResourceServerProperties resourceServerProperties;
    /**
     * 客户端属性
     */
    @Resource
    private OAuth2ClientProperties oAuth2ClientProperties;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests()
                .antMatchers("/oauth/**").permitAll()
                .anyRequest().authenticated();//任何连接只要认证后放行
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources
                .tokenServices(tokenServices())

                // 无效token异常类重写
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                // 权限不足异常类重写
                .accessDeniedHandler(new CustomAccessDeniedHandler());
    }

    /**
     * 默认资源服务器获取当前登录用户的username
     * 添加该方法后可以获取到与授权服务器一样的用户信息
     */
    @Bean
    @Primary
    public ResourceServerTokenServices tokenServices() {
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        remoteTokenServices.setCheckTokenEndpointUrl(resourceServerProperties.getTokenInfoUri());
        remoteTokenServices.setClientId(oAuth2ClientProperties.getClientId());
        remoteTokenServices.setClientSecret(oAuth2ClientProperties.getClientSecret());
        remoteTokenServices.setRestTemplate(restTemplate());

        DefaultAccessTokenConverter defaultAccessTokenConverter = new DefaultAccessTokenConverter();
        defaultAccessTokenConverter.setUserTokenConverter(new CommonUserConverter());
        remoteTokenServices.setAccessTokenConverter(defaultAccessTokenConverter);
        return remoteTokenServices;
    }

    /**
     * 创建新的restTemplate
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
        List<HttpMessageConverter<?>> convertersValid = new ArrayList<>();
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter || converter instanceof MappingJackson2XmlHttpMessageConverter) {
                continue;
            }
            convertersValid.add(converter);
        }
        convertersValid.add(new FastJsonHttpMessageConverter());
        restTemplate.setMessageConverters(convertersValid);
        return restTemplate;
    }
}

重写UserAuthenticationConverter

/**
 * 根据Token获取用户信息 与DefaultUserAuthenticationConverter同集成,优先该方法
 * @author king
 */
public class CommonUserConverter implements UserAuthenticationConverter {

    private static final String N_A = "N/A";

    /**
     * 将授权信息返回到资源服务
     *
     * @param authentication
     * @return
     */
    @Override
    public Map<String, ?> convertUserAuthentication(Authentication authentication) {
        Map<String, Object> authMap = new LinkedHashMap<>();
        authMap.put(USERNAME, authentication.getName());
        if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
            authMap.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
        }
        return authMap;
    }

    /**
     * 获取用户认证信息
     *
     * @param map
     * @return
     */
    @Override
    public Authentication extractAuthentication(Map<String, ?> map) {
        if (map.containsKey(USERNAME)) {
            Collection<? extends GrantedAuthority> authorities = getAuthorities(map);

            String userId = (String) map.get("id");
            String username = (String) map.get("username");
            LoginUser user = new LoginUser(userId, username, N_A, true, true, true, true, authorities);
            return new UsernamePasswordAuthenticationToken(user, N_A, authorities);
        }
        return null;
    }

    /**
     * 获取权限资源信息
     *
     * @param map
     * @return
     */
    private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
        Object authorities = map.get(AUTHORITIES);
        if (authorities instanceof String) {
            return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
        }
        if (authorities instanceof Collection) {
            return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils.collectionToCommaDelimitedString((Collection<?>) authorities));
        }
        throw new IllegalArgumentException("Authorities must be either a String or a Collection");
    }
}

如果出现问题

import org.springframework.security.oauth2.provider.token.RemoteTokenServices;

点进RemoteTokenServices中,打断点测试
在这里插入图片描述
在这里插入图片描述

最后

在配置restTemplate的时候要清掉自带的xml返回值类型,要不然restTemplate会只得到xml参数,导致解析成map时里面全部为String,导致验证失败
这个方法配置起来比较麻烦,但是还是可以用的,如果嫌麻烦,该方法比较简单 user-info-uri方式移步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vace cc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值