Skip to main content

快速开始/常规WEB应用/Java Spring Boot/

Java Spring Boot

Spring Boot 和 Spring Security 本身就支持 OIDC, 您无需额外给应用添加库依赖。 本指南演示了如何将 Authok 与任何新的或现有的Spring Boot 2 web应用程序进行集成。 我们推荐您参考此文为您的帐户配置示例。

使用 Spring WebFlux?

tip

初次使用Authok? 了解 Authok是如何工作的, 如何把Authok集成到普通WEB应用.

配置回调URL

配置 Logout URL

配置 Spring Boot 应用程序

添加 Spring 依赖

plugins {
id 'java'
id 'org.springframework.boot' version '2.3.0.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'

Maven的的配置

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/>
</parent>

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

配置 Spring Security

# src/main/resources/application.yml
spring:
security:
oauth2:
client:
registration:
authok:
client-id: YOUR_CLIENT_ID
client-secret: YOUR_CLIENT_SECRET
scope:
- openid
- profile
- email
provider:
authok:
# trailing slash is important!
issuer-uri: https://YOUR_DOMAIN/

在应用中添加登录

package com.authok.example;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.oauth2Login();
}
}
tip

可以进一步配置 HttpSecurity 实例. 指定认证的路由规则. 比如, 除了主页意外的所有路径都需要认证.

http.authorizeRequests()
.mvcMatchers("/").permitAll()
.anyRequest().authenticated()
.and().oauth2Login();

Spring Security 会使用先前的应用配置来处理登录. 你可以构造登录链接.

<!-- src/main/resources/templates/index.html -->
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<body>
<div sec:authorize="!isAuthenticated()">
<a th:href="@{/oauth2/authorization/authok}">Log In</a>
</div>
<div sec:authorize="isAuthenticated()">
<p>登录成功!</p>
</div>
</body>
</html>

创建一个 controller 来渲染视图;

package com.authok.example;

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

/**
* Controller for the home page.
*/
@Controller
public class HomeController {
@GetMapping("/")
public String home(Model model, @AuthenticationPrincipal OidcUser principal) {
return "index";
}
}

给应用添加注销

package com.authok.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* 需要在 Authok 执行 单点注销. 默认, Spring 会清除 SecurityContext 和 session.
* 此控制器同时会调用 Authok 的 logout 端点 来退登用户.
*/
@Controller
public class LogoutHandler extends SecurityContextLogoutHandler {

private final ClientRegistrationRepository clientRegistrationRepository;

/**
* 创建一个新的 {@code ClientRegistrationRepository} 实例.
* @param clientRegistrationRepository the {@code ClientRegistrationRepository} for this application.
*/
@Autowired
public LogoutHandler(ClientRegistrationRepository clientRegistrationRepository) {
this.clientRegistrationRepository = clientRegistrationRepository;
}

/**
* 委托 {@linkplain SecurityContextLogoutHandler} 进行退登.
*
* @param httpServletRequest the request.
* @param httpServletResponse the response.
* @param authentication the current authentication.
*/
@Override
public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Authentication authentication) {

// Invalidate the session and clear the security context
super.logout(httpServletRequest, httpServletResponse, authentication);

// 构造 URL 从 Authok 注销用户并重定向用户到主页.
// URL 类似 https://YOUR-DOMAIN/v1/logout?clientId=YOUR-CLIENT-ID&return_to=http://localhost:3000
String issuer = (String) getClientRegistration().getProviderDetails().getConfigurationMetadata().get("issuer");
String clientId = getClientRegistration().getClientId();
String returnTo = ServletUriComponentsBuilder.fromCurrentContextPath().build().toString();

String logoutUrl = UriComponentsBuilder
.fromHttpUrl(issuer + "v2/logout?client_id={clientId}&returnTo={returnTo}")
.encode()
.buildAndExpand(clientId, returnTo)
.toUriString();

try {
httpServletResponse.sendRedirect(logoutUrl);
} catch (IOException ioe) {
// Handle or log error redirecting to logout URL
}
}

/**
* 获取 Spring ClientRegistration 实例, which we use to get the registered client ID and issuer for building the
* {@code returnTo} query parameter when calling the Authok logout API.
*
* @return the {@code ClientRegistration} for this application.
*/
private ClientRegistration getClientRegistration() {
return this.clientRegistrationRepository.findByRegistrationId("authok");
}
}

接下来, 你需要实现 WebSecurityConfigurerAdapter 来注册 logout 处理器并指定触发 logout 的请求路径 (/logout).

package com.authok.example;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private final LogoutHandler logoutHandler;

public SecurityConfig(LogoutHandler logoutHandler) {
this.logoutHandler = logoutHandler;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Login()
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.addLogoutHandler(logoutHandler);
}
}

更新视图,添加一个 注销按钮:

<div sec:authorize="isAuthenticated()">
<p>您已经注销!</p>
<a th:href="@{/logout}">注销</a>
</div>

获取用户详情

@Controller
public class HomeController {

@GetMapping("/")
public String home(Model model, @AuthenticationPrincipal OidcUser principal) {
if (principal != null) {
model.addAttribute("profile", principal.getClaims());
}
return "index";
}
}

可以在视图中展示用户信息:

<div sec:authorize="isAuthenticated()">
<img th:src="${profile.get('picture')}" th:attr="alt=${profile.get('name')}"/>
<h2 th:text="${profile.get('name')}"></h2>
<p th:text="${profile.get('email')}"></p>
<a th:href="@{/logout}">Log Out</a>
</div>