请求地址:localhost:40150/oauth/token/?grant_type=mobile_password

请求头, Basic 是 client_id 和 client_secret

请求参数

TokenEndpoint#postAccessToken 报错There is no client authentication. Try adding an appropriate authentication filter.

    @RequestMapping(value = "/oauth/token", method=RequestMethod.POST)public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal,@RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {if (!(principal instanceof Authentication)) {throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");}// 省略代码...}

报错原因:/oauth/token/ 改成 /oauth/token, 因为结尾多了斜杆 / 导致

DefaultSecurityFilterChain#matches 匹配不上

    /**DefaultSecurityFilterChain#matches*/public boolean matches(HttpServletRequest request) {return requestMatcher.matches(request);}

1. 抽象过滤器:OncePerRequestFilter#doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)

// 找到这个方法 this = WebMvcMetricsFilter
this.doFilterInternal(httpRequest, httpResponse, filterChain);

2. ApplicationFilterChain#doFilter 调用 internalDoFilter

    @Overridepublic void doFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {if( Globals.IS_SECURITY_ENABLED ) {...}else {internalDoFilter(request,response);}}

internalDoFilter 取出过滤器 调用 FilterChainProxy#doFilter

2. FilterChainProxy#doFilter 方法里面调用 doFilterInternal 关键方法 getFilters 这里返回具体的过滤器

    @Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {doFilterInternal(request, response, chain);}private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) {// 获取过滤器List<Filter> filters = getFilters(fwRequest);}private List<Filter> getFilters(HttpServletRequest request) {for (SecurityFilterChain chain : filterChains) {if (chain.matches(request)) {return chain.getFilters();}}return null;}

WebSecurity#performBuild 把 FilterChainProxy.filterChains 初始化, 如下图,最关键是 filters

看到有两个实现类, 里面的filters,那到底选择哪个filters, 又是如何选择的

FilterChainProxy#getFilters, 遍历 filterChains,根据request 匹配正则来确定选 filters

   private List<Filter> getFilters(HttpServletRequest request) {for (SecurityFilterChain chain : filterChains) {if (chain.matches(request)) {return chain.getFilters();}}return null;}

重点来了,报错根本原因就是这个 chain.matches(request) 我的请求 request = /oauth/token/, OrRequestMatcher [requestMatchers=[Ant [pattern=‘/oauth/token’], Ant [pattern=‘/oauth/token_key’], Ant [pattern=‘/oauth/check_token’]]] OrRequestMatcher.requestMatchers [Ant [pattern=‘/oauth/token’]],导致request = /oauth/token/ 和 pattern='/oauth/token’匹配不上 选错了filters, 具体看图

OrRequestMatcher#matches, 返回 false, 进入下一个循环

   public boolean matches(HttpServletRequest request) {for (RequestMatcher matcher : requestMatchers) {if (logger.isDebugEnabled()) {logger.debug("Trying to match using " + matcher);}if (matcher.matches(request)) {logger.debug("matched");return true;}}logger.debug("No matches found");return false;}

AnyRequestMatcher#matches 直接返回true

    public boolean matches(HttpServletRequest request) {return true;}

FilterChainProxy#doFilterInternal 关键的类 VirtualFilterChain,把刚filters 设置到里面,

private void doFilterInternal(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {...VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);// 调用doFilter, 然后挨个匹配 filters 列表的filter, 找到对应的vfc.doFilter(fwRequest, fwResponse);
}

VirtualFilterChain#doFilter, 把 filters 的过滤器匹配

   @Overridepublic void doFilter(ServletRequest request, ServletResponse response) {if (currentPosition == size) {...} else {currentPosition++;Filter nextFilter = additionalFilters.get(currentPosition - 1);nextFilter.doFilter(request, response, this);}}

AnyRequestMatcher对应的filters

[
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter,
org.springframework.security.web.context.SecurityContextPersistenceFilter,
org.springframework.security.web.header.HeaderWriterFilter,
org.springframework.security.web.authentication.logout.LogoutFilter,
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter,
org.springframework.security.web.session.SessionManagementFilter,
org.springframework.security.web.access.ExceptionTranslationFilter,
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
]

OrRequestMatcher对应的filters

[
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter,
org.springframework.security.web.context.SecurityContextPersistenceFilter,
org.springframework.security.web.header.HeaderWriterFilter,
org.springframework.security.web.authentication.logout.LogoutFilter,
org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter,
org.springframework.security.web.authentication.www.BasicAuthenticationFilter,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter,
org.springframework.security.web.session.SessionManagementFilter,
org.springframework.security.web.access.ExceptionTranslationFilter,
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
]

因为我请求 Basic 要选择 BasicAuthenticationFilter处理才是正确的,也因为 request = /oauth/token/ 和 pattern='/oauth/token’匹配不上选错了filters,导致找不到对应的filter 处理,最终导致 TokenEndpoint的请求参数principal 为空 抛出 throw new InsufficientAuthenticationException(“There is no client authentication. Try adding an appropriate authentication filter.”); 至此报错原因,源码级别分析到此结束

    @RequestMapping(value = "/oauth/token", method=RequestMethod.POST)public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal,@RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {if (!(principal instanceof Authentication)) {throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");}// 省略代码...}

断点的类

end 谢谢

oauth2源码级别解析报错原因:There is no client authentication. Try adding an appropriate authentication filter相关推荐

  1. mysql 5.6.23 源码包安装报错_大环境下MySQL5.6源码安装实战一步步教你 CentOS6.5_64bit下编译安装...

    一.关闭防火墙 chkconfig iptables off service iptables stop 二.检查操作系统上是否安装了MySQL [[email protected] backup]# ...

  2. centos7源码安装mysql报错_CentOS7 下源码安装MySQL数据库 8.0.11

    本文主要向大家介绍了CentOS7 下源码安装MySQL数据库 8.0.11,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助. CentOS7 下源码安装MySQL 8.0.11 系 ...

  3. 风格迁移1-02:Liquid Warping GAN(Impersonator)-源码模型测试-报错解决

    以下链接是个人关于Liquid Warping GAN(Impersonator)-姿态迁移,所有见解,如有错误欢迎大家指出,我会第一时间纠正.有兴趣的朋友可以加微信:17575010159 相互讨论 ...

  4. 补单平台开发搭建源码_补单系统开发搭建IDEA导入jdk8源码学习(报错解决方案)

    补单系统功能介绍 一.买家端 1.本套系统可以获取客户通讯录,方式买家跑单骗单: 2.任务大厅:买家可以在任务大厅选择自己觉得佣金和平台适合自己的订单操作: 3.已接任务:可以查看我们所接的订单,以及 ...

  5. 试用补单平台源码_补单系统开发搭建IDEA导入jdk8源码学习(报错解决方案)

    补单系统功能介绍 一.买家端 1.本套系统可以获取客户通讯录,方式买家跑单骗单: 2.任务大厅:买家可以在任务大厅选择自己觉得佣金和平台适合自己的订单操作: 3.已接任务:可以查看我们所接的订单,以及 ...

  6. centos7源码安装mysql报错_centos7.3源码安装mysql

    环境说明: 该系统第一次安装mysql. 自己指定安装目录,指定数据文件目录. linux系统版本:CentOS 7.3 64位 安装源文件版本:mysql-5.7版本 mysql安装位置:/soft ...

  7. mysql 5.6.23 源码包安装报错_CentOS6.5_64bit下编译安装MySQL-5.6.23

    ************************************************************ CentOS6.5_64bit下编译安装MySQL-5.6.23 ****** ...

  8. mysql 5.6.23 源码包安装报错_Ubuntu 14.10下编译安装MySQL 5.6.23

    1. 安装环境: Ubuntu Server 14.10 MySQL-5.6.23.tar.gz 2. 安装必备的工具 sudo apt-get install make bison g++ buil ...

  9. 搭建spark源码运行环境报错及解决办法

    报错1: \Restfull\spark\external\flume-sink\src\main\scala\org\apache\spark\streaming\flume\sink\Loggin ...

最新文章

  1. jQuery.click()与onClick
  2. 异地备份同步校验脚本
  3. TTL传输中过期的解决办法
  4. Java反射机制Reflection
  5. 遇见未来 | 超融合如何兼顾企业的“敏态”和“稳态”的业务需求
  6. 重磅消息:全球首个光量子计算机诞生!
  7. python数据驱动测试设计_GitHub - 13691579846/DataDriverTestFrameWork: python+selenium+pageobject数据驱动测试框架...
  8. mongodb教程_MongoDB教程
  9. EndNote X7集成到office word2016(原有EndNote选项卡,却突然消失)
  10. ir2104s的自举电容_有关IR2104的自举电容和NMOS选择问题.docx
  11. RTE2020首批嘉宾公布 技术+行业专家携手顶级投资人参会
  12. ffmpeg.wasm前端实现多张图片合成视频
  13. Window提高效率的软件
  14. matlab如何去除图像白边_matlab 图像保存时去除白边
  15. 软考必考之有关计算机的知识产权基础
  16. dubbo-admin0.3.0安装教程
  17. ESP32 之 ESP-IDF 教学(五(2))——使用C++的工程
  18. Python爬虫selenium抓取Xbox
  19. android模拟器failed to make and chown /acct/uid: Read-only file system的原因
  20. 基于python的图像格式转换(将RGB图像转换为灰度图像)

热门文章

  1. 魔戒啊魔戒,请帮我解开CDM的“数据魔法”
  2. 基于Solr的智能化物联网与智能智能安防平台平台
  3. atof、stof 用法
  4. 已解决-Office365邮箱默认的保存时长策略最长只有6个月
  5. iOS UI设计模版收藏
  6. $slots.default
  7. 永磁同步电机矢量控制(FOC)之:电压前馈补偿型电流控制方案
  8. 网络游戏服务器设计浅析
  9. 新风系统风速推荐表_新风系统送风口风速怎么选择 新风系统送风口风速选择标准【详解】...
  10. 零基础能否转行做程序员,那些半路出家的程序员大神给你做了榜样