ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

oauth2 问题 Full authentication is required to access this resource 探索

2022-07-12 20:03:50  阅读:302  来源: 互联网

标签:Full resource access oauth2 logout 401 http HttpSecurity


问题现象

启用oauth2后,正常的oauth2 登录都是没有问题的,但是我想 form登录呢? 其实也是支持的,不过我开始是没搞明白,一直出现问题 Full authentication is required to access this resource, 几天都搞不定,茶不思饭不想...

 

 

 

单独使用spring security是ok 的,所以感觉是 加了 oauth2 导致的,说实在话,oauth2的源码看过,但没有完全搞懂。后面F12 查看请求信息, 发现:

总体信息:
Request URL: http://192.168.1.103:8081/auth/
Request Method: GET
Status Code: 401 
Remote Address: 192.168.1.103:8081


响应头:
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Headers: x-requested-with, authorization
Access-Control-Allow-Methods: *
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 3600
Cache-Control: no-store
Content-Type: application/xhtml+xml
Date: Mon, 11 Jul 2022 23:12:46 GMT
Pragma: no-cache
Transfer-Encoding: chunked
WWW-Authenticate: Bearer realm="oauth2-resource", error="unauthorized", error_description="Full authentication is required to access this resource"
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block


请求头:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,zh-HK;q=0.7,en;q=0.6
Cache-Control: max-age=0
Connection: keep-alive
Cookie: JSESSIONID=EAFF5C06541EE532098D58B1D5D097A1; JSESSIONID=D06EF1CF20C1D3413BD8DA26D2279A5E
Host: 192.168.1.103:8081
Referer: http://192.168.1.103:8081/auth/myLogin
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36

 

发现响应状态码是 401。后面又注意到 响应头包含有WWW-Authenticate 这个意味着什么?  查看了响应体, 竟然没有内容, why ?

观察发现请求头、参数并不包含 Authentication: Bearer xxx token, 

Authentication 是不是我之前使用 basic 登录的残留? 使用ff浏览器试试?

结果发现其实是一样的。

 

源码调试

关键字是:
WWW-Authenticate: Bearer realm="oauth2-resource", error="unauthorized", error_description="Full authentication is required to access this resource"

通过关键字跟踪源码调试半天发现是这里问题: 

其实里面是触发了 AccessDeniedException,

 

 

不只是 http://192.168.1.103:8081/auth/ , 任何url,比如 http://192.168.1.103:8081/auth/123456789 都是 401
unauthorized 表明已经认证, 但是没有授权吧; 确实如此,登录就是认证,但是权限呢?并没有发放出来..

对于 resource Server, 里面的所有访问都被看做是资源, 就访问url 就是访问资源, 是需要授权的。。 ———— 这一点在哪里有配置呢? OAuth2AuthenticationManager !
—— AuthorizationServer 期望就是每次访问都携带一个 Authentication: Bearer xxx token, 但是没有发现。 这里的逻辑是 OAuth2AuthenticationProcessingFilter#doFilter
BearerTokenExtractor#extract/#extractToken,首先是从header 里面获取,然后是从 request param获取

最后到达 ExceptionTranslationFilter#handleSpringSecurityException:185 的 sendStartAuthentication 方法, 也就是创建了一个InsufficientAuthenticationException, 然后

最后是:OAuth2AuthenticationEntryPoint ,然后, AbstractOAuth2SecurityExceptionHandler#doHandle , OAuth2AuthenticationEntryPoint#enhanceResponse


我确实已经登录了, 但是却发现 principal: anonymousUser, sessionId 是正确的 446631399D1901E4CF3E50EF5AB94EBB

isAllowSessionCreation() = false

测试 request.isRequestedSessionIdValid() 结果  true

 

原因其实是
AuthorizationServerSecurityConfiguration#configure(HttpSecurity)

 

 

 

这里,默认是 never ,也就是说,就即使登录了, 也不会创建。 这个可怎么办啊,

 我想在 我的AuthServerConfig#configure( AuthorizationServerSecurityConfigurer)方法里面尝试配置

.and() .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)

结果发现 参数的 AuthorizationServerSecurityConfigurer 还没有初始化, 没有设置 HttpSecurity, and 方法无法执行。

 

试试给我的 WebSecurityConfigurerAdapter 的configure(HttpSecurity http) 方法设置一下

 

 

 发现不起作用!

 

问题解决

发现原因

protected void configure(HttpSecurity http) throws Exception {

http.requestMatchers()
            .antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated();
 }

 

原因就是配置 初始的authorizeRequests.antMatchers 必须要包括所有的配置受formLogin 保护的资源端点,否则就会走 oauth2 认证;oauth2 会读取请求头或请求参数里面的Authentication: Bearer xxx token,读取不到就直接 deny, 返回401.

所以呢,问题解决方案就是受formLogin 保护的资源端点, 不配置且不放行则 401; 当然,oauth2的端点不需要配置在这里,否则画蛇添足导致oauth2登录不正常!

    protected void configure(HttpSecurity http) throws Exception {
        http
                .headers().frameOptions().disable()
                .and()
                .csrf().disable()

                // 配置受formLogin 保护的资源端点, 不配置且不放行则 401; 当然,oauth2的端点不需要配置在这里,否则画蛇添足导致oauth2登录不正常!
                .requestMatchers()
                .antMatchers("/myLogin","/doLogin", "/oauth/authorize"
                        , "/protected/**", "/mustLogin/**", "/securedPage*"
                        , "/myLogout*" , "/logout?logout*" // login?logout 也需要保护起来,否则401 —— 这样也不行 todo
                        // 首页也最好保护起来,否则..
                        , "/", "/index", "/tourist*", "/a*")// 这里antMatchers必须要包括/doLogin, 否则永远都是登录页面
                .and()
                .authorizeRequests()

                //antMatchers这里 "/user/me"不能放行,如果放行,则不能获取到Principal参数 —— 错错错,再次测试发现 这里 "/user/me"是否放行 都不要紧; 不知道哪里搞错了
                .antMatchers("/tourist","/myLogin", "/logout?logout*", "/doLogin","/user/me123", "/oauth/authorize")
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/myLogin")
                // 它的作用是什么? 仅仅是一个通知作用吧..不对! 测试发现,只有配置了loginPage,那么就一定需要配置loginProcessingUrl, 而且需要匹配!
                .loginProcessingUrl("/doLogin")
                .defaultSuccessUrl("/index", false)
                .permitAll()
//                .and()
//                .authorizeRequests()
//                .anyRequest().authenticated() // 不能加这行,
//                否则:一直401 <oauth><error_description>Full authentication is required to access this resource</error_description><error>unauthorized</error></oauth>
        .and()
        .logout()

        // 设置logoutUrl之后,再访问/logout会出现401(如果不放行), 或者404
        // 测试发现, /myLogout、 /logout 两个端点都可以注销成功,why? 按理说只有一个;  测试发现如果antMatchers 发现/logout,则只有logoutUrl可以注销,而且访问 /logout不会注销,而是404
        // 测试发现有时候/myLogout 并没真正的注销,而是401,why? 原因是logoutUrl需要受保护
        // 这里需要 保护起来, 否则也是 401, Full authentication is required to access this resource
        .logoutUrl("/myLogout")
        // defaultTarget must start with '/' or with 'http(s)'
        .logoutSuccessUrl("/myLogoutSuccessUrl")
        .permitAll()
        // .logoutSuccessHandler(tigerLogoutSuccessHandler)  //url和Handler只能配置一个
//        .deleteCookies("JSESSIONID")//清除cook键值

        .and()

        // 这里的sessionManagement 并不能影响到AuthorizationServer, 因为..
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
        ;

    }

那为什么这样配置之后就ok了呢?因为requestMatchers 必须要包括了某端点才会对她进行认证、校验,否则就不管它, 就会被其他的HttpSecurity 捕获到,进而引发意外问题 。

 

多个 HttpSecurity

其实调试过程中是发现有3个 HttpSecurity,分别对应3个AuthorizationServerConfigurerAdapter,分别来自自定义的MySecurityConfiguration,及 ResourceServerConfiguration、AuthorizationServerSecurityConfiguration 他们各司其职,都有其作用,非常合理。

但是每个 HttpSecurity 可以有自己的一系列的配置, 包括 session管理, 比如 oauth2 就不需要 session, 所以策略是 never 。

如果有多个 HttpSecurity, 那么? 会覆盖吗?其实是会的,他们有一个顺序。

 

整个过程下来,人其实很累,不过很有收获。我发现就是spring框架的命名, 极其的规范、考究!初看非常懵, 其实 看似复杂, 却非常合理! 越看越轻松, 看懂后 恍然大悟、 醍醐灌顶, 拍手称赞, 膜拜得五体投地 !!不过缺点 就是概念太多太细了!!

而且代码量那么大, 如不学会跳读, 那么肯定坚持不下去的, 肯定看不完,容易失去耐心。

 

标签:Full,resource,access,oauth2,logout,401,http,HttpSecurity
来源: https://www.cnblogs.com/FlyAway2013/p/16471446.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有