oauth2
“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。
在构建Web应用程序时,必须进行身份验证和授权。 然而,正确地做起来并不容易。 计算机安全是真正的专业。 众多开发人员昼夜不停地与众多国际黑客进行对抗,从而创造了一个持续的开发周期,以发现漏洞,对其进行攻击并加以修复。 跟上所有这些独奏会很痛苦(如果不是不可能的话)。
幸运的是,没有必要。 Spring Security和Spring Boot使使用OAuth 2.0实施Web应用程序变得非常简单。 Okta,即软件即服务的身份访问提供商,已经在Spring Boot的基础上进行了构建,从而使这一过程变得更加容易。
在本教程中,您将首先使用Spring Boot和Spring Security构建OAuth 2.0 Web应用程序和身份验证服务器。 之后,您将使用Okta摆脱自我托管的身份验证服务器,并进一步简化Spring Boot应用程序。
让我们开始吧!
创建一个OAuth 2.0服务器
首先转到Spring Initializr并使用以下设置创建一个新项目:
- 将项目类型从Maven更改为Gradle 。
- 将组更改为com.okta.spring 。
- 将工件更改为AuthorizationServerApplication 。
- 添加一个依赖项: Web 。
下载项目并将其复制到硬盘上有意义的位置。 在本教程中,您将创建三个不同的项目,因此您可能需要创建一个父目录,例如SpringBootOAuth
。
您需要向build.gradle
文件添加一个依赖build.gradle
:
implementation 'org.springframework.security.oauth:spring-security-oauth2:2.3.3.RELEASE'
这增加了Spring的OAuth优势。
更新src/main/resources/application.properties
以使其匹配:
server.port=8081
server.servlet.context-path=/auth
user.oauth.clientId=R2dpxQ3vPrtfgF72
user.oauth.clientSecret=fDw7Mpkk5czHNuSRtmhGmAGL42CaxQB9
user.oauth.redirectUris=http://localhost:8082/login/oauth2/code/
user.oauth.user.username=Andrew
user.oauth.user.password=abcd
这将设置服务器端口,servlet上下文路径以及服务器将返回给客户端的内存中临时生成的令牌以及我们用户的用户名和密码的一些默认值。 在生产中,您将需要更多用于真正的身份验证服务器的复杂后端,而没有硬编码的重定向URI,用户名和密码。
更新AuthorizationServerApplication
类以添加@EnableResourceServer
:
package com.okta.spring.AuthorizationServerApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
@SpringBootApplication
@EnableResourceServer
public class AuthorizationServerApplication {
public static void main(String[] args) {
SpringApplication.run(AuthorizationServerApplication.class, args);
}
}
在与src/main/java
下的应用程序类com.okta.spring.AuthorizationServerApplication
相同的包中创建一个新的AuthServerConfig
类(从现在开始,请在src/main/java/com/okta/spring/AuthorizationServerApplication
创建Java类)。 此Spring配置类启用并配置OAuth授权服务器。
package com.okta.spring.AuthorizationServerApplication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Value("${user.oauth.clientId}")
private String ClientID;
@Value("${user.oauth.clientSecret}")
private String ClientSecret;
@Value("${user.oauth.redirectUris}")
private String RedirectURLs;
private final PasswordEncoder passwordEncoder;
public AuthServerConfig(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
@Override
public void configure(
AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(ClientID)
.secret(passwordEncoder.encode(ClientSecret))
.authorizedGrantTypes("authorization_code")
.scopes("user_info")
.autoApprove(true)
.redirectUris(RedirectURLs);
}
}
AuthServerConfig
类是在客户端正确进行身份验证时将创建并返回我们的JSON Web令牌的类。
创建一个SecurityConfiguration
类:
package com.okta.spring.AuthorizationServerApplication;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@Order(1)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value("${user.oauth.user.username}")
private String username;
@Value("${user.oauth.user.password}")
private String password;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(username)
.password(passwordEncoder().encode(password))
.roles("USER");
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
SecurityConfiguration
类是实际验证对授权服务器的请求的类。 注意顶部附近是从application.properties
文件中提取用户名和密码的地方。
最后,创建一个名为UserController
的Java类:
package com.okta.spring.AuthorizationServerApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
@RestController
public class UserController {
@GetMapping("/user/me")
public Principal user(Principal principal) {
return principal;
}
}
该文件允许客户端应用程序查找有关通过服务器进行身份验证的用户的更多信息。
那就是你的资源服务器! 还不错Spring Boot使其非常容易。 四个文件和一些属性。 稍后,您将使用Okta使其变得更加简单,但是目前,继续创建可用于测试身份验证服务器的客户端应用程序。
启动授权服务器:
./gradlew bootRun
等待它完成运行。 终端应该以这样的结尾:
...
2019-02-23 19:06:49.122 INFO 54333 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path '/auth '
2019-02-23 19:06:49.128 INFO 54333 --- [ main] c.o.s.A.AuthorizationServerApplication : Started AuthorizationServerApplication in 3.502 seconds (JVM running for 3.945)
注意:如果收到有关JAXB的错误( java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
),那是因为您正在使用build.gradle
。要解决此问题,请将JAXB添加到build.gradle
。
implementation 'org.glassfish.jaxb:jaxb-runtime'
构建您的客户端应用
回到Spring Initializr 。 使用以下设置创建一个新项目:
- 项目类型应为Gradle (不是Maven)。
- 组: com.okta.spring 。
- 工件: SpringBootOAuthClient 。
- 添加三个依赖项: Web , Thymeleaf , OAuth2 Client 。
下载项目,将其复制到最终的放置位置,然后解压缩。
这次,您需要将以下依赖项添加到build.gradle
文件中:
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE'
将src/main/resources/application.properties
重命名为application.yml
并更新它以匹配以下YAML:
server:
port: 8082
session:
cookie:
name: UISESSION
spring:
thymeleaf:
cache: false
security:
oauth2:
client:
registration:
custom-client:
client-id: R2dpxQ3vPrtfgF72
client-secret: fDw7Mpkk5czHNuSRtmhGmAGL42CaxQB9
client-name: Auth Server
scope: user_info
provider: custom-provider
redirect-uri-template: http://localhost:8082/login/oauth2/code/
client-authentication-method: basic
authorization-grant-type: authorization_code
provider:
custom-provider:
token-uri: http://localhost:8081/auth/oauth/token
authorization-uri: http://localhost:8081/auth/oauth/authorize
user-info-uri: http://localhost:8081/auth/user/me
user-name-attribute: name
请注意,这里您正在配置clientId
和clientSecret
以及身份验证服务器的各种URI。 这些需要与另一个项目中的值匹配。
更新SpringBootOAuthClientApplication
类以匹配:
package com.okta.spring.SpringBootOAuthClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootOAuthClientApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootOAuthClientApplication.class, args);
}
}
创建一个名为WebController
的新Java类:
package com.okta.spring.SpringBootOAuthClient;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.security.Principal;
@Controller
public class WebController {
@RequestMapping("/securedPage")
public String securedPage(Model model, Principal principal) {
return "securedPage";
}
@RequestMapping("/")
public String index(Model model, Principal principal) {
return "index";
}
}
这是将传入请求映射到您的Thymeleaf模板文件(您将在几秒钟内完成)的控制器。
创建另一个名为SecurityConfiguration
Java类:
package com.okta.spring.SpringBootOAuthClient;
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 SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests()
.antMatchers("/", "/login**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
此类为您的应用程序定义了Spring Security配置:允许本地路径上的所有请求并要求对所有其他路由进行身份验证。 它还设置了Spring Boot OAuth登录流程。
您需要添加的最后一个文件是两个Thymeleaf模板文件。 全面了解Thymeleaf模板超出了本教程的范围,但是您可以查看其网站以获取更多信息。
模板位于src/main/resources/templates
目录中。 您会在上方的控制器中注意到,它们只是返回路线的字符串。 当Thymeleaf依赖项包含在构建中时,Spring Boot会自动假定您正在从控制器中返回模板文件的名称,因此该应用程序将在src/main/resources/templates
查找包含返回字符串加号的文件名。 .html
。
创建主页模板: src/main/resources/templates/index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<h1>Spring Security SSO</h1>
<a href="securedPage">Login</a>
</body>
</html>
以及受保护的模板: src/main/resources/templates/securedPage.html
:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Secured Page</title>
</head>
<body>
<h1>Secured Page</h1>
<span th:text="${#authentication.name}"></span>
</body>
</html>
我只是指出这一行:
<span th:text="${#authentication.name}"></span>
这行将插入已验证用户的名称。 这行是为什么在build.gradle
文件中需要org.thymeleaf.extras:thymeleaf-extras-springsecurity5
依赖项的build.gradle
。
启动客户端应用程序:
./gradlew bootRun
等待它完成。 终端应该以这样的结尾:
...
2019-02-23 19:29:04.448 INFO 54893 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8082 (http) with context path ''
2019-02-23 19:29:04.453 INFO 54893 --- [ main] c.o.s.S.SpringBootOAuthClientApplication : Started SpringBootOAuthClientApplication in 3.911 seconds (JVM running for 4.403)
测试资源服务器
在您选择的浏览器中导航至http://localhost:8082/
客户端应用程序。
单击登录链接。
您将被定向到登录页面:
输入用户名Andrew和密码abcd (来自身份验证服务器的application.properties
文件)。
单击“登录” ,您将进入超级精美的securePage.html模板,其中应显示“ Secured Page”和“ Andrew”。
大! 有用。 现在,您将使其变得更加简单。
您可以停止服务器和客户端Spring Boot应用程序。
创建一个OpenID Connect应用程序
Okta是SaaS(软件即服务)身份验证和授权提供者。 我们为开发人员提供免费帐户,以便他们可以轻松开发OIDC应用程序。 前往developer.okta.com并注册一个帐户。 验证电子邮件后,登录并执行以下步骤:
- 转到应用程序>添加应用程序。
- 选择应用程序类型Web ,然后单击下一步。
- 为应用命名。 我将其命名为“ Spring Boot OAuth”。
- 在登录重定向URI下,将值更改为
http://localhost:8080/login/oauth2/code/okta
。 其余的默认值将起作用。 - 单击完成。
让页面保持打开状态,注意客户端ID和客户端密钥。 稍后您将需要它们。
创建一个新的Spring Boot App
再回到Spring Initializr 。 使用以下设置创建一个新项目:
- 将项目类型从Maven更改为Gradle 。
- 将组更改为com.okta.spring 。
- 将工件更改为OktaOAuthClient 。
- 添加三个依赖项: Web , Thymeleaf , Okta 。
- 单击生成项目。
复制项目并将其解压缩到某个地方。
在build.gradle
文件中,添加以下依赖项:
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE'
另外,在您到那里时,请注意com.okta.spring:okta-spring-boot-starter:1.1.0
依赖com.okta.spring:okta-spring-boot-starter:1.1.0
。 这是Okta Spring Boot Starter。 这是一个方便的项目,可以轻松轻松地将Okta与Spring Boot集成。 有关更多信息,请查看项目的GitHub 。
将src/main/resources/application.properties
更改为application.yml
并添加以下内容:
server:
port: 8080
okta:
oauth2:
issuer: https://{yourOktaDomain}/oauth2/default
client-id: {yourClientId}
client-secret: {yourClientSecret}
spring:
thymeleaf:
cache: false
请记住,当我说您需要上面的ClientID和Client Secret时。 好,时间到了。 您需要将它们以及Okta发行者URL填充到文件中。 它看起来像这样: dev-123456.okta.com
。 您可以在API >授权服务器下找到它。
在src/main/resources/templates
目录中,您还需要两个类似的模板文件。 index.html
模板文件完全相同,并且可以根据需要复制。 由于您从Okta返回身份验证信息的方式与您之前构建的简单身份验证服务器相比, securedPage.html
模板文件略有不同。
创建主页模板: src/main/resources/templates/index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<h1>Spring Security SSO</h1>
<a href="securedPage">Login</a>
</body>
</html>
以及受保护的模板: src/main/resources/templates/securedPage.html
:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Secured Page</title>
</head>
<body>
<h1>Secured Page</h1>
<span th:text="${#authentication.principal.attributes.name}">Joe Coder</span>
</body>
</html>
在com.okta.spring.SpringBootOAuth
包中创建一个名为WebController
的Java类:
package com.okta.spring.OktaOAuthClient;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.security.Principal;
@Controller
public class WebController {
@RequestMapping("/securedPage")
public String securedPage(Model model, Principal principal) {
return "securedPage";
}
@RequestMapping("/")
public String index(Model model, Principal principal) {
return "index";
}
}
该类仅创建两个路由,一个用于本地路由,一个用于安全路由。 再一次,Spring Boot和Thymeleaf将其自动修改为src/main/resources/templates
的两个模板文件。
最后,创建另一个Java类,名称为SecurityConfiguration
:
package com.okta.spring.OktaOAuthClient;
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 SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
而已! am!
运行由Okta-OAuth支持的客户端:
./gradlew bootRun
您应该看到一堆以结尾的输出:
...
2019-02-23 20:09:03.465 INFO 55890 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-02-23 20:09:03.470 INFO 55890 --- [ main] c.o.s.O.OktaOAuthClientApplication : Started OktaOAuthClientApplication in 3.285 seconds (JVM running for 3.744)
单击登录按钮。
这次,您将被带到Okta登录页面。 您可能需要使用隐身浏览器或在此处注销developer.okta.com仪表板,以免跳过登录页面并立即定向到安全端点。
登录,您将看到带有您的姓名的安全页面!
了解有关Spring Boot,Spring Security和OAuth 2.0的更多信息
就是这样。 超级容易。 在上一教程中,您研究了如何使用Spring Boot和Spring Security来实现非常基本的身份验证服务器和客户端应用程序。 接下来,您使用Okta使用功能齐全的SSO和OAuth身份验证制作一个更简单的客户端应用程序。
您可以在oktadeveloper / okta-spring-boot-authz-server-example上的GitHub上查看本教程的完整代码。
如果您想了解有关Spring Boot,OAuth 2.0和Spring Security的更多信息,请查看以下有用的教程:
- Spring Boot,OAuth 2.0和Okta入门
- OAuth到底是什么?
- Spring Security 5.0和OIDC入门
- 身份,声明和令牌– OpenID Connect入门手册,第1部分,共3部分
- 使用Spring Boot和GraphQL构建安全的API
如果您对此帖子有任何疑问,请在下面添加评论。 有关更多精彩内容,请在Twitter上关注@oktadev ,或订阅我们的YouTube频道!
“带有Spring Security的OAuth 2.0快速指南”最初于2019年3月发布在Okta开发者博客上。
“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。
翻译自: https://www.javacodegeeks.com/2019/03/quick-guide-oauth-spring-security.html
oauth2