spring security +oauth2(授权服务和资源服务分离) 解决getPrincipal只返回用户名的问题

spring security +oauth2(授权服务和资源服务分离) 解决getPrincipal只返回用户名的问题,第1张

spring security +oauth2(授权服务和资源服务分离) 解决getPrincipal只返回用户名的问题

      最近用spring security + oauth2 做认证和授权,碰到个非常懊恼的问题,从安全上下文获取用户信息,永远只给你返回个用户名。因为在很多地方,要用到用户id, 不可能又用用户名去数据库查id吧,这就非常蛋腾了。

     百度了人民群众的意见,折腾了老半天,终于把它搞掂了。

    终极大法就是重写源码里面默认的实现方法。

    源码就不贴了, 这贴修改的,供各位参考参考:

   一 、 重写DefaultUserAuthenticationConverter里面的convertUserAuthentication方法:

@Component
@Slf4j
public class SetAdditionalInfoToTokenConverter extends DefaultUserAuthenticationConverter {
    
    

   @Override
    public Map convertUserAuthentication(Authentication authentication) {
        Map response = new linkedHashMap();
       // response.put(USERNAME, authentication.getName());   源码里面的,不知道USERNAME是什么,注释掉吧
       Object principal = authentication.getPrincipal();
       
       //不要强制转换principal, 用json转化,不然各种莫名其妙的坑
       String jsonStr=JSON.toJSonString(principal);
       JSonObject jsonObject=JSON.parseObject(jsonStr);
       
       //加上自定义的用户名和id
       long id=jsonObject.getLong("id");
        response.put("id", id);
        String username=jsonObject.getString("username");
        response.put("username",username);

        if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
            response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
        }
        return response;
    }
    
    
    //懒得写, 从源码复制过来的
    private Collection getAuthorities(Map map) {
        if (!map.containsKey(AUTHORITIES)) {
            return List.of();
        }
        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");
    }
    
}

      

  二,把这个重写的类 SetAdditionalInfoToTokenConverter 设置到授权服务器配置类里面 :

      

   SetAdditionalInfoToTokenConverter  ----> defaultAccessTokenConverter ->jwtAccessTokenConverter--->endpints.tokenEnhancer()

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Qualifier("customUserDetailService")
    @Autowired

    private UserDetailsService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    SetAdditionalInfoToTokenConverter setAdditionalInfoToTokenConverter; //定制保存在jwt里面的信息


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

    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setAccessTokenConverter(accessTokenConverter());
        return jwtAccessTokenConverter;
    }

    @Bean
    public DefaultAccessTokenConverter accessTokenConverter(){
        DefaultAccessTokenConverter defaultAccessTokenConverter = new 
                                                  DefaultAccessTokenConverter();
     defaultAccessTokenConverter.setUserTokenConverter(setAdditionalInfoToTokenConverter);
        return defaultAccessTokenConverter;
    }


}

 三, 上面两步只是把额外信息(用户id,用户名)设置进jwtoken, 还不能用get principal获取,我们再继续重写 DefaultUserAuthenticationConverte 里面的 extractAuthentication方法,这个方法实现怎样提取信息到anthentication。因为后面要把重写的类设置进资源服务器配置类里面,所以重新创建一个component: ExtractAuthenticationConverter

@Component
@Slf4j
public class ExtractAuthenticationConverter extends DefaultUserAuthenticationConverter {

    
    @Override
    public Authentication extractAuthentication(Map map) {
           String username="username";
           String id="id";
           Map principal=new HashMap<>();
            if(map.containsKey(username)){
                 principal.put(username, map.get(username));
            }
            if(map.containsKey(id)){
                principal.put(id, map.get(id));
            }

            Collection authorities = getAuthorities(map);
            return new UsernamePasswordAuthenticationToken(principal, "N/A", authorities);
    }

    //从源码复制过来的
    private Collection getAuthorities(Map map) {
        if (!map.containsKey(AUTHORITIES)) {
            return List.of();
        }
        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");
    }
    
}

 四、 把重写了 extractAuthentication的类 extractAuthenticationConverter 设置进资源服务器配置类: 

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Autowired
    ExtractAuthenticationConverter extractAuthenticationConverter;


    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(jwtTokenStore());

    }

    private TokenStore jwtTokenStore() {
        JwtTokenStore jwtTokenStore = new JwtTokenStore(accessTokenConverter());
        return jwtTokenStore;
    }

    @Bean 
    public JwtAccessTokenConverter accessTokenConverter() {
       
        JwtAccessTokenConverter tokenConverter = new JwtAccessTokenConverter();
        //如果用了公私钥,在这里解析公钥。。。 省略

        // 新建一个defaultAccessTokenConverter中介把 自定义的extractAuthenticationConverter设置进去
       DefaultAccessTokenConverter defaultAccessTokenConverter = new DefaultAccessTokenConverter();
       defaultAccessTokenConverter.setUserTokenConverter(extractAuthenticationConverter);
       tokenConverter.setAccessTokenConverter(defaultAccessTokenConverter);
        return tokenConverter;
    }

}

  至此,全部设置完,建个接口测试一下:

    @GetMapping("/principle")
    public Object getUserInfo(){
        return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }

     返回  :

{

    "id": 12312154321,

    "username": "admin"

}

 ok,成功。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5609594.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存