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

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

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

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

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

@Component
@Slf4j
public class SetAdditionalInfoToTokenConverter extends DefaultUserAuthenticationConverter {/*** 这个方法把额外的信息添加进jwt token (默认只添加用户名,权限)* 这里额外添加了用户id* 方法将会在授权服务器起作用* @param authentication* @return*/@Overridepublic Map<String, ?> convertUserAuthentication(Authentication authentication) {Map<String, Object> response = new LinkedHashMap<String, Object>();// response.put(USERNAME, authentication.getName());   源码里面的,不知道USERNAME是什么,注释掉吧Object principal = authentication.getPrincipal();//不要强制转换principal, 用json转化,不然各种莫名其妙的坑String jsonStr=JSON.toJSONString(principal);JSONObject jsonObject=JSON.parseObject(jsonStr);//加上自定义的用户名和idlong 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<? extends GrantedAuthority> getAuthorities(Map<String, ?> 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 {@Autowiredprivate AuthenticationManager authenticationManager;@Qualifier("customUserDetailService")@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate PasswordEncoder passwordEncoder;@AutowiredSetAdditionalInfoToTokenConverter setAdditionalInfoToTokenConverter; //定制保存在jwt里面的信息@Overridepublic 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;}@Beanpublic 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 {/*** 这个方法重新定义了安全上下文 securityContextHolder.getContext.getPrincipal 返回的信息;*  默认只返回用户名*  这里添加了返回用户id*  方法在资源服务器起作用* @param map* @return*/@Overridepublic Authentication extractAuthentication(Map<String, ?> map) {String username="username";String id="id";Map<String,Object> principal=new HashMap<>();if(map.containsKey(username)){principal.put(username, map.get(username));}if(map.containsKey(id)){principal.put(id, map.get(id));}Collection<? extends GrantedAuthority> authorities = getAuthorities(map);return new UsernamePasswordAuthenticationToken(principal, "N/A", authorities);}//从源码复制过来的private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> 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 {@AutowiredExtractAuthenticationConverter extractAuthenticationConverter;@Overridepublic 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,成功。

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

  1. 将Spring Security OAuth2授权服务JWK与Consul 配置中心结合使用

    将Spring Security OAuth2授权服务JWK与Consul 配置中心结合使用 概述 在前文中介绍了OAuth2授权服务简单的实现密钥轮换,与其不同,本文将通过Consul实现我们的目的 ...

  2. 使用Spring Security Oauth2 和 JWT保护微服务--Uaa授权服务器的编写

    学习自深入理解微服务 采用Spring Security OAuth2 和 JWT的方式,Uaa服务只需要验证一次,返回JWT.返回的JWT包含了用户的所有信息,包括权限信息 从三个方面讲解: JWT ...

  3. 《深入理解 Spring Cloud 与微服务构建》第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统

    <深入理解 Spring Cloud 与微服务构建>第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统 文章目录 <深入理解 Spring Cl ...

  4. Spring Security Oauth2 授权码模式下 自定义登录、授权页面

    主要说明:基于若依springcloud微服务框架的2.1版本 嫌弃缩进不舒服的,直接访问我的博客站点: http://binarydance.top//aticle_view.html?aticle ...

  5. Spring Security OAuth2 授权码模式 (Authorization Code)

    前言 Spring Security OAuth2 授权码模式 (Authorization Code) 应该是授权登录的一个行业标准 整体流程 首先在平台注册获取CLIENT_ID和CLIENT_S ...

  6. Spring Security Oauth2 授权服务开发

    2019独角兽企业重金招聘Python工程师标准>>> 集成开发环境 ·开发工具:Eclipse/Myeclipse/IntelliJ IDEA 任选其一 ·运行环境:jdk1.7及 ...

  7. Spring Security OAuth2 授权失败(401)

    Spring Cloud架构中采用Spring Security OAuth2作为权限控制,关于OAuth2详细介绍可以参考 http://www.ruanyifeng.com/blog/2014/0 ...

  8. spring security oauth2 授权服务器负载均衡解决方案

    研究了好几天的授权服务对资源服务是如何实现负载均衡的 真的是丈二和尚摸不着头脑,研究了几天今天终于找到了一篇文章 真的是翻:烂了 奈何自己太菜 上一下资源服务的yml配置(oauth-server是注 ...

  9. 使用Spring Security Oauth2 和 JWT保护微服务--资源服务器的编写

    编写hcnet-website的资源服务 依赖管理pom文件 hcnet-website工程的pom文件继承主maven的pom文件.在hcnet-website工程的pom文件中添加web功能的起步 ...

  10. OAuth2授权客户端访问资源服务

    OAuth客户端访问资源服务 一.简介 在单点登录一文,我们是通过注解@EnableOAuth2Sso实现单点登录的,我们了解到OAuth2获取token的方式是通过OAuth2RestOperati ...

最新文章

  1. Win32 ASM 简单对话框编程Demo
  2. 美国大学生数学建模竞赛 细节问题(23条)汇总!!!
  3. Chrome 渲染流水线演化的未来
  4. DataNode之文件系统数据集FsVolumeList
  5. MPICH C语言接口函数说明
  6. [C++] - private static成员函数
  7. 【Elasticsearch】es Ingest 节点
  8. Unicode,ANSI,UTF-8的故事
  9. POJ3414 Pots —— BFS + 模拟
  10. 关于JavaScript DOM 编程艺术这本书
  11. 编写c语言程序解一元一次方程,一元方程计算器1.0的代码(C语言实现)
  12. Filezilla server 使用教程
  13. 中国网络视频前景 表面云淡风轻实在暗潮汹涌
  14. 计算机和网络之间有个感叹号,电脑连接网络显示感叹号,教你电脑连接网络显示感叹号怎么办...
  15. 爬虫实战(一)-新版知乎网页分析获取登录url
  16. 微信小程序连接第三方接口
  17. html5直播服务端搭建,直播推流服务器端搭建
  18. 启动模式,BOOT0和BOOT1详解
  19. 东华OJ进阶题47 最少拦截系统
  20. 认识oracle的update更新

热门文章

  1. 洛谷 P5713 【深基3.例5】洛谷团队系统 C语言
  2. WordpressCMS主题开发04-如何在首页调用各个分类下的文章以及图片栏目
  3. The Economist 《经济学人》常用词汇总结
  4. bzoj4816 [Sdoi2017]数字表格(反演)
  5. 2009年毕业设计题目:网上自助装机系统的设计与实现
  6. 苹果手机为什么Apple ID会被停用
  7. Blue Coat:2015年数据安全趋势七大预测
  8. 紫光视频平台服务器系统,紫光展锐打造操作系统生态,赋能万物互联智能时代...
  9. win10将用户文件夹改为英文
  10. 计算机大赛鼓励语录,比赛加油鼓励经典语录