使用Spring Security连接Google的OpenID进行身份验证

Spring Security5中包含了一个简单地使用OpenID Connect的功能。(在Spring文件中称为OAuth2.0登录。)

尤其是与Google、GitHub、Facebook和Okta的集成,只需进行简单的设定即可运行。本次我们尝试使用Google进行操作,以下是相关内容。

如果您对OpenID Connect一无所知的话,以下文章将会对您非常有帮助:
https://qiita.com/TakahikoKawasaki/items/498ca08bbfcc341691fe

谷歌方面的准备

按照以下页面的指示,进行Google OpenID Connect的设置:
https://developers.google.com/identity/protocols/OpenIDConnect

简单解释一下,大致感觉如下。

    1. 前往Google API控制台。

 

    1. 從「認證資訊」選擇「建立認證資訊」→選擇「OAuth用戶端ID」。

 

    1. 應用程式類型和名稱可以隨意填寫。

 

    在已授權的重定向URI中添加http://localhost:8080/login/oauth2/code/google。

请根据您自己创建应用程序的环境来调整最后的重定向URI的协议、主机名和端口号。由于”/login/oauth2/code/google”的部分是Spring Security的默认设置,如果要更改默认行为,则还需要更改此部分。

应用程序的设置

本次我们将使用Spring Boot来创建应用程序。

pom.xml – 請提供POM檔案

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>oidc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>oidc</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

除了Spring Security之外,还需要spring-security-oauth2-client和spring-security-oauth2-jose。由于Spring Initializr无法添加它们,因此需要手动修改pom.xml文件。此外,由于本次使用Thymeleaf来进行页面显示,因此需要添加Thymeleaf和用于Spring Security的Thymeleaf扩展的依赖关系。

应用程序.yml

这次我们将使用yml进行设置,但也可以使用properties进行相同的设置。

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: [クライアントID]
            client-secret: [クライアントシークレット]

请复制并粘贴Google创建的认证信息中的客户端ID和客户端密钥。

应用程序类

暂时使用默认设置没有问题。OpenID Connect相关的设置也会自动配置。

@SpringBootApplication
public class OidcApplication {

    public static void main(String[] args) {
        SpringApplication.run(OidcApplication.class, args);
    }
}

控制器

为了确认动作,我们将创建一个Controller类。(也可以在主类内创建。)

@Controller
public class HelloController {

  @GetMapping("/")
  public String index(@AuthenticationPrincipal OidcUser user, Model model) {
    model.addAttribute("username", user.getFullName());
    return "hello";
  }

认证信息存储在OidcUser对象中,可以使用getName()方法获取唯一ID。(不太喜欢叫Name。)
此外,还可以获取头像链接和电子邮件地址。

虽然OidcUser类提供了许多方法来获取生日等各种数据,但Google并不会返回所有相关数据,因此有一些方法是无法使用的(会返回null)。

百里香叶

我們將建立一個顯示認證資訊的畫面。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
  <head>
    <title>OpenID Connect Sample</title>
    <meta charset="utf-8"/>
  </head>

  <body>
    <div>名前:<span sec:authentication="principal.attributes['name']"></span></div>
    <div>名前:<span th:text="${username}"></span></div>
    <div>ID:<span sec:authentication="principal.name"></span></div>
  </body>
</html>

顺便提一句,当使用sec:authentication=”principal.fullName”时会出错。
因为在控制器中使用了getFullName方法,所以认为可以访问,但事实却不是这样。
尝试使用其他的get…方法时,有些会引发错误,有些则不会。

getFullName等已经在IdTokenClaimAccessor接口中默认实现了,但是只有默认实现的方法似乎无法调用。

我花了一些时间追踪源代码,发现BeanWrapperImpl利用Introspector收集BeanInfo并进行访问。
然后,根据下面的链接,似乎Introspector不支持接口的默认实现。
https://bugs.openjdk.java.net/browse/JDK-8071693

确认行动

image.png
無題.png

只需要按照以上的方式,就可以非常容易地实现OpenID Connect!

我認為管理使用者的密碼是一件非常麻煩且令人擔憂的事情,因此很多人可能希望使用OpenID Connect。由於Spring Security可以處理大部分繁瑣的工作,因此導入Spring Security的門檻也會降低。

广告
将在 10 秒后关闭
bannerAds