使用 Spring Security OAuth2 和 Vaadin 流程登录 21

Posted

技术标签:

【中文标题】使用 Spring Security OAuth2 和 Vaadin 流程登录 21【英文标题】:Login with Spring Security OAuth2 and Vaadin flow 21 【发布时间】:2021-12-22 13:41:19 【问题描述】:

我正在尝试为我的 Discord Bot 创建一个 Web 界面,并希望添加一个“使用 Discord 登录”方法。我创建了两个视图来测试 OAuth 登录系统。

第一个视图是索引/主页视图,其中包含“不和谐登录”按钮。

@PageTitle("Home")
@Route(value = "")
@AnonymousAllowed
public class HomeView extends VerticalLayout 
    private final OAuth2AuthorizedClientService clientService;

    public HomeView(OAuth2AuthorizedClientService clientService) 
        this.clientService = clientService;
        setSpacing(false);
        setPadding(false);
        add(navbar());
        add(body());
    

    private Component navbar() 
        HorizontalLayout root = new HorizontalLayout();
        root.setWidthFull();
        root.setAlignItems(Alignment.CENTER);
        Span name = new Span("Unity");
        name.getStyle().set("padding-left", "1rem");
        root.add(name);

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (!(authentication instanceof OAuth2AuthenticationToken)) 
            Button loginButton = new Button();
            Image discordLogo = new Image("images/discord.svg", "discord_logo.png");
            discordLogo.getStyle().set("padding-top", "0.5rem");
            loginButton.setIcon(discordLogo);
            loginButton.setText("Login with Discord");
            loginButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
            loginButton.getStyle().set("padding-right", "1rem");
            loginButton.addClassName("toolbar");
            Anchor anchor = new Anchor("/oauth2/authorization/discord", loginButton);
            anchor.getElement().setAttribute("router-ignore", true);
            root.add(anchor);
         else 
            Notification.show("Logged In");
            OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
            OAuth2AuthorizedClient client = this.clientService.loadAuthorizedClient(token.getAuthorizedClientRegistrationId(), token.getName());
            String accessToken = client.getAccessToken().getTokenValue();
            Notification.show("Logged in with token: " + accessToken);
        

        root.setFlexGrow(1, name);
        root.addClassNames("contrast-5pct");

        return root;
    


    private Component body() 
        VerticalLayout root = new VerticalLayout();
        Image img = new Image("images/empty-plant.png", "placeholder plant");
        img.setWidth("200px");
        root.add(img);

        root.add(new H2("This place intentionally left empty"));
        root.add(new Paragraph("It’s a place where you can grow your own UI ????"));

        root.setSizeFull();
        root.setJustifyContentMode(JustifyContentMode.CENTER);
        root.setDefaultHorizontalComponentAlignment(Alignment.CENTER);
        root.getStyle().set("text-align", "center");

        return root;
    

另一个视图是用户认证成功后的视图。

@Route("test")
public class TestView extends VerticalLayout 
    public TestView() 
        add("It Works! :D");
    

我当前的 spring oauth 配置如下所示:

spring:
  security:
    oauth2:
      client:
        registration:
          discord:
            client-id: <id>
            client-secret: <secret>
            clientAuthenticationMethod: post
            authorizationGrantType: authorization_code
            scope:
              - identify
              - guilds
            redirectUri: "baseUrl/login/oauth2/callback/registrationId"
            clientName: Discord-Client
        provider:
          discord:
            authorizationUri: https://discordapp.com/api/oauth2/authorize
            tokenUri: https://discordapp.com/api/oauth2/token
            userInfoUri: https://discordapp.com/api/users/@me
            usernameAttribute: username

我的 Spring Security 配置如下所示:

@Configuration
public class SecurityConfig extends VaadinWebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.authorizeRequests().antMatchers("/oauth2/authorization/discord", "/login/oauth2/callback/**").permitAll();
        http.oauth2Login(oauth -> 
            oauth.defaultSuccessUrl("/test");
            )
            .logout(logout -> 
                logout.logoutSuccessUrl("/");
            );

        super.configure(http);
    

    @Override
    public void configure(WebSecurity web) throws Exception 
        super.configure(web);
        web.ignoring().antMatchers(
            "/images/**"
        );
    

    @Bean
    public RestOperations restOperations() 
        return new RestTemplate();
    

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception 
        return super.authenticationManager();
    

我已尝试实施此帖子中的解决方案:Spring Oauth2 client with Google provider keep asking for authentication,但它不断将我重定向到主视图并且用户未通过身份验证。

我是否缺少对用户进行身份验证的内容!?

提前感谢您的帮助!

【问题讨论】:

这个问题太复杂,无法在 *** 中完整回答。 Vaadin 在这里有带有 Google 登录 /w Spring Security 的 OAuth2 示例vaadin.com/learn/tutorials/google-login 我建议您研究该示例并将身份验证提供程序替换为 Discord。如果您没有成功,请在此处提出更具体的问题以寻求帮助。 这能回答你的问题吗? Spring Oauth2 client with Google provider keep asking for authentication @TatuLund 我尝试使用 [vaadin.com/learn/tutorials/google-login](vaadin.com/learn/tutorials/google-login 教程) 教程,但它似乎不起作用在 vaadin 21 上。我会陷入登录请求循环并且永远不会获得身份验证(/test 视图总是将我重定向到 oauth 登录) @EleftheriaStein-Kousathana 感谢您提及该帖子。我已经尝试实施该解决方案,并且不再被困在该登录循环中。遗憾的是,由于某种原因,用户不会被重定向到 defaultSuccessUrl 或经过身份验证。 【参考方案1】:

我已经解决了我的问题。我的 redirectUri 错了^^"

将其从 baseUrl/login/oauth2/callback/registrationId 更改为 baseUrl/login/oauth2/code/registrationId 后,它可以正常工作

【讨论】:

以上是关于使用 Spring Security OAuth2 和 Vaadin 流程登录 21的主要内容,如果未能解决你的问题,请参考以下文章

使用 spring-session 和 spring-cloud-security 时,OAuth2ClientContext (spring-security-oauth2) 不会保留在 Redis

针对授权标头的Spring Security OAuth2 CORS问题

使用spring security jwt spring security oauth2权限控制遇到的坑记录

Spring Security 入门(1-3)Spring Security oauth2.0 指南

Spring Security OAuth2 - 如何使用 OAuth2Authentication 对象?

oauth2 spring-security 如果您在请求令牌或代码之前登录