获取 GitHub OAuth2 登录所需的 client-id 和 client-secret
- 登录 GitHub:使用你的 GitHub 账号登录到 GitHub。
- 访问开发者设置:点击右上角的头像,选择
Settings
,然后在左侧导航栏中选择Developer settings
。 - 创建新的 OAuth 应用:在 Developer settings 中,选择 OAuth Apps,然后点击
New OAuth App
。 - 填写应用信息:
Application name:为你的应用取一个名称。
Homepage URL:应用的主页 URL。
Authorization callback URL:用户授权后重定向的 URL。这个 URL 必须是你应用中能够处理授权回调的有效 URL。 - 注册应用:填写完信息后,点击
Register application
。 - 获取 client-id 和 client-secret:注册成功后,你会看到应用的 Client ID 和 Client Secret。注意,Client Secret 只会显示一次,务必妥善保存。
在 Spring Boot 中配置 OAuth2:
- 在 pom.xml 中引入如下依赖
<!-- 能够让用户避免在Web站点特定的登录页上自己输入凭证信息。这样的Web站点提供了一种通过其他网站(如Facebook)登录的方式,用户可能已经在这些其他的网站登录过了。
这种类型的认证是基于OAuth2或OpenID Connect(OIDC)的。OAuth2是一个授权规范,例如使用它来保护REST API,但它也可以用来通过第三方网站实现认证功能。
OpenID Connect是另一个基于OAuth2的安全规范,用于规范化第三方认证过程中发生的交互。 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
- 在application.properties中添加如下配置
# Spring Security内置了针对Facebook、Google、GitHub和Okta的登录方式,但你也可以通过指定一些额外的属性来配置其他客户端。
# 要让我们的应用成为OAuth2或OpenID Connect的客户端,有一些通用的属性需要设置,如下所示:
# 客户端ID和secret是用来标识我们的应用在Facebook中的凭证。你可以在Facebook的开发者网站新建应用来获取客户端ID和secret。scope属性可以用来指定应用的权限范围。
# 所有工作:1.引入oauth2依赖 2.配置客户端id和secret以及scope,这就是所有工作,当访问需要认证的页面时,会自动跳转到facebook登录页面
# 如果通过声明SecurityFilterChain bean来自定义安全配置,那么除了其他的安全配置,还需要启用OAuth2登录。
spring.security.oauth2.client.registration.github.client-id=<client id>
spring.security.oauth2.client.registration.github.client-secret=<client secret>
spring.security.oauth2.client.registration.github.scope=<scope>
在SecurityConfig配置类中通过SecurityFilterChain配置HttpSecurity启用OAuth2
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
/*
* HttpSecurity可以配置很多的功能,其中包括:●要求在为某个请求提供服务之前,满足特定的安全条件;●配置自定义的登录页;●使用户能够退出应用;●预防跨站请求伪造。
* HttpSecurity最常见的需求就是拦截请求以确保用户具备适当的权限。
* */
return http
.authorizeRequests()
.antMatchers("/design", "/orders").hasRole("USER")
// .antMatchers("/design", "/orders").access("hasRole('USER') or hasRole('ADMIN')")
.antMatchers("/", "/**").permitAll()
// 为了替换内置的登录页,我们首先需要告诉Spring Security自定义登录页的路径。这可以通过调用HttpSecurity对象的formLogin()方法来实现,如下所示:
.and().formLogin().loginPage("/login")
// // 声明Spring Security要监听对“/authenticate”的请求来处理登录信息的提交。同时,用户名和密码的字段名应该是user和pwd。
// .loginProcessingUrl("/authenticate").usernameParameter("user").passwordParameter("pwd")
// // 如果用户登录成功,就会被重定向到“/design”路径。
// .defaultSuccessUrl("/design", true)
// 如果通过声明SecurityFilterChain bean来自定义安全配置,那么除了其他的安全配置,还需要启用OAuth2登录,如下所示:
.and().oauth2Login()
.and().build();
/* 表5.1 用来定义如何保护路径的配置方法
| 方法 | 功能 |
| -------------------------- | ------------------------------------------------------------ |
| access(String) | 如果给定的SpEL(代表Spring ExpressionLanguage)表达式计算结果为true,就允许访问 |
| anonymous() | 允许匿名用户访问 |
| authenticated() | 允许认证过的用户访问 |
| denyAll() | 无条件拒绝所有访问 |
| fullyAuthenticated() | 如果用户进行了完整认证(而不是通过Rememberme功能认证的),就允许访问 |
| hasAnyAuthority(String...) | 如果用户具备给定权限中的某一个,就允许访问 |
| hasAnyRole(String...) | 如果用户具备给定角色中的某一个,就允许访问 |
| hasAuthority(String) | 如果用户具备给定权限,就允许访问 |
| hasIpAddress(String) | 如果请求来自给定IP,就允许访问 |
| hasRole(String) | 如果用户具备给定角色,就允许访问 |
| not() | 对其他访问方法的结果求反 |
| permitAll() | 无条件允许访问 |
| rememberMe() | 如果用户是通过Remember-me功能认证的,就允许访问 |
* 我们还可以使用access()方法,通过为其提供SpEL表达式来声明更丰富的安全规则。Spring Security扩展了SpEL,包含多个安全相关的值和函数,如表5.2所示。
* 表5.2 Spring Security对Spring表达式语言的扩展
| 安全表达式 | 计算结果 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| authentication | 用户的认证对象 |
| denyAll | 结果始终为false |
| hasAnyAuthority(String...authorities) | 如果用户被授予了给定权限中的任意一个,结果为true |
| hasAnyRole(String.. roles) | 如果用户具有给定角色中的任意一个,结果为true |
| hasAuthority(String authority) | 如果用户被授予了给定的权限,结果为true |
| hasPermission(Object target, Object permission) | 如果用户能够访问特定目标对象以获取给定权限,结果为true |
| hasPermission(Serializable targetId String targetType,Objeotpermission) | 如果用户能够访问targetId和targetType中给定的象以获取给定权限,结果为true |
| hasRole(String role) | 如果用户被授予了给定的角色,结果为true |
| hasIpAddress(String ipAddress) | 如果请求来自给定IP,结果为true |
| isAnonymous() | 如果用户为匿名用户,结果为true |
| isAuthenticated() | 如果用户进行了认证,结果为true |
| isFullyAuthenticated() | 如果用户进行了完整认证(而不是通过Renember-me功能认证的),结果为true |
| isRememberMe() | 如果用户是通过Renemberme功能认证的,结果为true |
| permitAll | 结果始终为true |
| principal | 用户的principal对象
*/
}