专栏首页朝雨忆轻尘Spring Security OAuth2实现单点登录

Spring Security OAuth2实现单点登录

1、概述

在本教程中,我们将讨论如何使用 Spring Security OAuth 和 Spring Boot 实现 SSO(单点登录)。

本示例将使用到三个独立应用

  • 一个授权服务器(中央认证机制)
  • 两个客户端应用(使用到了 SSO 的应用)

简而言之,当用户尝试访问客户端应用的安全页面时,他们首先通过身份验证服务器重定向进行身份验证。

我们将使用 OAuth2 中的 Authorization Code 授权类型来驱动授权。

2、客户端应用

先从客户端应用下手,使用 Spring Boot 来最小化配置:

2.1、Maven 依赖

首先,需要在 pom.xml 中添加以下依赖:

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

2.2、安全配置

接下来,最重要的部分就是客户端应用的安全配置:

@Configuration
@EnableOAuth2Sso
public class UiSecurityConfig extends WebSecurityConfigurerAdapter {
     
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**")
          .authorizeRequests()
          .antMatchers("/", "/login**")
          .permitAll()
          .anyRequest()
          .authenticated();
    }
}

当然,该配置的核心部分是 @EnableOAuth2Sso 注解,我们用它来启用单点登录。

请注意,我们需要继承 WebSecurityConfigurerAdapter — 如果没有它,所有路径都将被保护 — 因此用户在尝试访问任何页面时将被重定向到登录页面。 在当前这个示例中,索引页面和登录页面可以在没有身份验证的情况下可以访问。

最后,我们还定义了一个 RequestContextListener bean 来处理请求。

application.yml

server:
    port: 8082
    context-path: /ui
    session:
      cookie:
        name: UISESSION
security:
  basic:
    enabled: false
  oauth2:
    client:
      clientId: SampleClientId
      clientSecret: secret
      accessTokenUri: http://localhost:8081/auth/oauth/token
      userAuthorizationUri: http://localhost:8081/auth/oauth/authorize
    resource:
      userInfoUri: http://localhost:8081/auth/user/me
spring:
  thymeleaf:
    cache: false

有几点需要说明:

  • 我们禁用了默认的 Basic Authentication
  • accessTokenUri 是获取访问令牌的 URI
  • userAuthorizationUri 是用户将被重定向到的授权 URI
  • 用户端点 userInfoUri URI 用于获取当前用户的详细信息

另外需要注意,在本例中,我们使用了自己搭建的授权服务器,当然,我们也可以使用其他第三方提供商的授权服务器,例如 Facebook 或 GitHub。

2.3、前端

现在来看看客户端应用的前端配置。我们不想把太多时间花费在这里

客户端应用有一个非常简单的前端:

index.html:

<h1>Spring Security SSO</h1>
<a href="securedPage">Login</a>

securedPage.html:

<h1>Secured Page</h1>
Welcome, <span th:text="${#authentication.name}">Name</span>

securedPage.html 页面需要用户进行身份验证。 如果未经过身份验证的用户尝试访问 securedPage.html,他们将首先被重定向到登录页面。

3、认证服务器

现在让我们开始来讨论授权服务器。

3.1、Maven 依赖

首先,在 pom.xml 中定义依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
</dependency>

3.2、OAuth 配置

理解我们为什么要在这里将授权服务器和资源服务器作为一个单独的可部署单元一起运行这一点非常重要。

让我们从配置资源服务器开始探讨:

@SpringBootApplication
@EnableResourceServer
public class AuthorizationServerApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(AuthorizationServerApplication.class, args);
    }
}

之后,配置授权服务器:

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager;
 
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()")
          .checkTokenAccess("isAuthenticated()");
    }
 
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
          .withClient("SampleClientId")
          .secret("secret")
          .authorizedGrantTypes("authorization_code")
          .scopes("user_info")
          .autoApprove(true) ; 
    }
 
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }
}

需要注意的是我们使用 authorization_code 授权类型来开启一个简单的客户端。

3.3、安全配置

首先,我们将通过 application.properties 禁用默认的 Basic Authentication:

server.port=8081
server.context-path=/auth
security.basic.enabled=false

现在,让我们到配置定义一个简单的表单登录机制:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Autowired
    private AuthenticationManager authenticationManager;
 
    @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.parentAuthenticationManager(authenticationManager)
          .inMemoryAuthentication()
          .withUser("john").password("123").roles("USER");
    }
}

请注意,虽然我们使用了简单的内存认证,但可以很简单地将其替换为自定义的 userDetailsService

3.4、用户端点

最后,我们将创建之前在配置中使用到的用户端点:

@RestController
public class UserController {
    @GetMapping("/user/me")
    public Principal user(Principal principal) {
        return principal;
    }
}

用户数据将以 JSON 形式返回。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • PHP代码安全策略

    php如果具有root权限,且在脚本中允许用户删除文件,那么用户提交数据,不进行过滤,就非常有可能删除系统文件

    luxixing
  • 100篇泛癌研究文献解读之lincRNA的生存分析情况

    为了分析不同类型、组织起源肿瘤的共性、差异以及新课题。TCGA于2012年10月26日-27日在圣克鲁兹,加州举行的会议中发起了泛癌计划。参考:https://...

    生信技能树
  • CentOS 7 部署RabbitMQ 服务

    版权声明:本文为木偶人shaon原创文章,转载请注明原文地址,非常感谢。 https://b...

    shaonbean
  • Java NIO-13.NIO Path

    Java Path接口是Java NIO2一部分,是对Java6 和Java7的更新。Java的Path接口在Java7中被添加到Java NIO中,位于jav...

    悠扬前奏
  • Gatsby入门指南—使用GraphQL解析Markdown(2)

    GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户...

    前端大彬哥
  • FSWD_1_BasicHtmlCss

    本文是香港中文大学《Full Stack Web Development》系列课程中的笔记

    用户1147754
  • SAP Web Console 对比 ITSMobile

    优点:集成于SAP,不需要额外的软硬件,稳定性好;界面可以修改格式,可以优化。支持匿名登录。

    用户5495712
  • cdn日志分析进阶(awk)

    参考: https://www.jianshu.com/p/db2f3dd162f1

    Mr.Du
  • SpringBoot 2.0 配置错误页面 原

    北漂的我
  • Python读写csv文件专题教程(2)

    如果我想修改age列的数据类型为float,read_csv时可以使用dtype调整,如下:

    double

扫码关注云+社区

领取腾讯云代金券