通过 MultiHttpSecurityConfig 实现“oauth2Login()”和“httpBasic()”同一页面

Posted

技术标签:

【中文标题】通过 MultiHttpSecurityConfig 实现“oauth2Login()”和“httpBasic()”同一页面【英文标题】:Implement "oauth2Login()" and "httpBasic()" same page via MultiHttpSecurityConfig 【发布时间】:2021-06-08 02:33:07 【问题描述】:

如果用户点击/api/*,会加载“formLogin()”页面;否则加载“httpBasic()”。此设置工作正常。下面是它的代码。

@Configuration
    public class SecurityConfig 

    @Configuration
    @Order(1)
    public static class SpecialSecurityConfig extends WebSecurityConfigurerAdapter 

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http
                .antMatcher("/api/**")
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .formLogin()
                    .loginPage("/api/login");         
        
        
        @Override
        public void configure(WebSecurity web) throws Exception 
          web.ignoring().antMatchers("/", "/css/**");
        
    

    @Configuration
    public static class RegularSecurityConfig extends WebSecurityConfigurerAdapter 

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .httpBasic();
        
        
        @Override
        public void configure(WebSecurity web) throws Exception 
          web.ignoring().antMatchers("/", "/css/**");
        
    

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
        auth.inMemoryAuthentication()
                .withUser("user")
                .password("nooppass")
                .roles("USER");
    

现在我想删除“formLogin()”并将其替换为“oauth2Login()”。之后,当我单击 google 链接时,它会加载“httpBasic()”登录页面。如果用户点击谷歌,它应该去谷歌登录页面。请帮我解决这个问题。下面是它的代码。

    http
    .antMatcher("/api/**")
    .authorizeRequests()
    .anyRequest().authenticated()
    .and()
    .oauth2Login()
    .loginPage("/api/oauth_login")
    .permitAll();

oauth_login.html

<body>
<div class="container">
<h1>Social Login</h1>
<p><a href="/oauth2/authorization/google">Google</a></p>
</div>
</body>

【问题讨论】:

【参考方案1】:

您指定匹配 "/api/**" 的请求应使用 OAuth 2 登录由 SpecialSecurityConfig 保护,所有其他请求应使用 HTTP 基本由 RegularSecurityConfig 保护。

由于"/oauth2/authorization/google""/api/**" 不匹配,因此使用HTTP basic 对其进行保护。

一种选择是将用于授权请求的基本 URI 更改为以 "/api/" 开头(默认为 "/oauth2/authorization/registrationId")。

您可能还想自定义loginProcessingUrlauthorizationRequestResolver

public void configure(HttpSecurity http) throws Exception 
    http
        .antMatcher("/api/**")
        .authorizeRequests(authorize -> authorize
            .anyRequest().authenticated()
        )
        .oauth2Login(oauth2 -> oauth2
            .loginProcessingUrl("/api/login/oauth2/code/*")
            .loginPage("/api/oauth_login")
            .authorizationEndpoint(ae -> ae
                .baseUri("/api/oauth2/authorization/registrationId")
                .authorizationRequestResolver(getAuthorizationRequestResolver())
            )
        );


private OAuth2AuthorizationRequestResolver getAuthorizationRequestResolver() 
    return new DefaultOAuth2AuthorizationRequestResolver(
        this.clientRegistrationRepository,
        "/api/oauth2/authorization");

然后您还将更新您的登录表单

<p><a href="/api/oauth2/authorization/google">Google</a></p>

【讨论】:

我按照您的建议更改了 Html 代码。之后,当我点击谷歌链接时,它会重定向到同一页面。 @Dinesh 您是否将安全配置中的baseUri 更新为以“/api”开头? 添加“baseUri("/api/oauth2/authorization/")”后,我可以加载谷歌登录页面。登录后,我收到带有 url localhost:8080/login/oauth2/code/… 的 Whitelabel 错误页面页面有什么想法吗? 您可能还想设置 loginProcessingUrl 和 authorizationRequestResolver。我已经更新了我的答案以包括那些。 添加这些更改后,我仍然遇到同样的错误。未找到资源已完成 404 NOT_FOUND【参考方案2】:

我参考以下网址并修改我的代码

Oauth2Login for only specific urls

http 
        .authorizeRequests()
        .antMatchers("/api/**").authenticated()        
        .anyRequest().authenticated()
        .and()
        .oauth2Login()
        .loginPage("/api/oauth_login")
        .defaultSuccessUrl("/api/home")
        .permitAll();

普通网址(/api/* 除外)也会加载谷歌登录页面。

【讨论】:

【参考方案3】:

禁用基本登录和表单登录。示例安全配置如下所示;

 .formLogin()
                .disable()
            .httpBasic()
                .disable()
            .exceptionHandling()
                .authenticationEntryPoint(new RestAuthenticationEntryPoint())
                .and()
            .authorizeRequests()
                .antMatchers("/auth/**", "/oauth2/**")
                    .permitAll()
                .anyRequest()
                    .authenticated()
                .and()
            .oauth2Login()
                .authorizationEndpoint()
                    .baseUri("/oauth2/authorize")
                    .and()
                .redirectionEndpoint()
                .baseUri("/oauth2/callback/*")

从前端调用此端点(Google/Facebook 按钮应链接到以下链接) http://localhost:8080/oauth2/authorize/provider?redirect_uri=

关注此guide。这正是您要寻找的。​​p>

【讨论】:

【参考方案4】:

现在我可以加载谷歌登录页面了。添加凭证后,页面重定向到白标错误页面。

Oauth2 代码

http
            .antMatcher("/api/**")
            .authorizeRequests(authorize -> authorize.anyRequest().authenticated())
            .oauth2Login(oauth2 -> oauth2.loginProcessingUrl("/api/login/oauth2/code/*")
                    .loginPage("/api/oauth_login").permitAll()
                    .authorizationEndpoint(a -> a.baseUri("/api/oauth2/authorization")
                            .authorizationRequestResolver(                                    
                                    getAuthorizationRequestResolver())
                            )
            );

错误->

2021-03-11 15:02:53.319 调试 11762 --- [nio-8080-exec-2] osweb.servlet.DispatcherServlet : GET "/login/oauth2/code/google?state=Ds-x92t6fpHo8BINK_xYba3fpidheKQSHBaTdctOPRE %3D&code=4%2F0AY0e-g6i-tfqlpBREW45ufRPQEOu-aM7VjIf7VzKOBVMSXrvLkaxB5U2A72dAOxxEUnN1Q&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com %2Fuserinfo.email&authuser=0&hd=wearenoetic.com&prompt=consent", parameters=masked

2021-03-11 15:02:53.321 调试 11762 --- [nio-8080-exec-2] oswshandler.SimpleUrlHandlerMapping :映射到 ResourceHttpRequestHandler [类路径资源 [META-INF/resources/],类路径资源[resources/]、类路径资源[static/]、类路径资源[public/]、ServletContext资源[/]]

2021-03-11 15:02:53.346 调试 11762 --- [nio-8080-exec-2] o.s.w.s.r.ResourceHttpRequestHandler:找不到资源

2021-03-11 15:02:53.346 调试 11762 --- [nio-8080-exec-2] os.web.servlet.DispatcherServlet:已完成 404 NOT_FOUND

2021-03-11 15:02:53.348 DEBUG 11762 --- [nio-8080-exec-2] osweb.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error?state=Ds-x92t6fpHo8BINK_xYba3fpidheKQSHBaTdctOPRE% 3D&code=4%2F0AY0e-g6i-tfqlpBREW45ufRPQEOu-aM7VjIf7VzKOBVMSXrvLkaxB5U2A72dAOxxEUnN1Q&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com 2Fuserinfo.email&authuser=0&hd=wearenoetic.com&prompt=consent",参数=masked

2021-03-11 15:02:53.349 调试 11762 --- [nio-8080-exec-2] swsmmaRequestMappingHandlerMapping:映射到 org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml( HttpServletRequest, HttpServletResponse)

2021-03-11 15:02:53.373 调试 11762 --- [nio-8080-exec-2] oswsvContentNegotiatingViewResolver:给定 [text/html, text/html;q=0.8] 选择的“text/html”

2021-03-11 15:02:53.374 DEBUG 11762 --- [nio-8080-exec-2] os.web.servlet.DispatcherServlet:退出“错误”调度,状态 404

【讨论】:

添加以下代码后,我可以解决这个问题 spring.security.oauth2.client.registration.google.redirect-uri=baseUrl/api/login/oauth2/code/registrationId

以上是关于通过 MultiHttpSecurityConfig 实现“oauth2Login()”和“httpBasic()”同一页面的主要内容,如果未能解决你的问题,请参考以下文章

下拉框多选框单选框 通过TagHelper绑定数据

酶:测试孩子通过安装渲染失败,但通过浅时通过

java是通过值传递,也就是通过拷贝传递——通过方法操作不同类型的变量加深理解

通过代码进行 Spring 配置与通过注释进行配置

如何理解“不要通过共享内存来通信,而应该通过通信来共享内存”?

通过邮递员通过 API 使用 Rails 主动存储上传文件(.pdf、.jpg 等)? (不通过 Rails 视图)