赞
踩
在本教程中,我们将讨论如何使用 Spring Security OAuth 和 Spring Boot 实现 SSO(单点登录)。
本示例将使用到三个独立应用
一个授权服务器(中央认证机制)
两个客户端应用(使用到了 SSO 的应用)
简而言之,当用户尝试访问客户端应用的安全页面时,他们首先通过身份验证服务器重定向进行身份验证。
我们将使用 OAuth2 中的 Authorization Code 授权类型来驱动授权。
先从客户端应用下手,使用 Spring Boot 来最小化配置:
首先,需要在 pom.xml 中添加以下依赖:
<code class="language-plaintext hljs"><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> </code>
接下来,最重要的部分就是客户端应用的安全配置:
<code class="language-plaintext hljs">@Configuration
@EnableOAuth2Sso
public class UiSecurityConfig extends WebSecurityConfigurerAdapter { @Overridepublic void configure(HttpSecurity http) throws Exception {http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**").permitAll().anyRequest().authenticated();}
} </code>
当然,该配置的核心部分是 @EnableOAuth2Sso 注解,我们用它来启用单点登录。
请注意,我们需要继承 WebSecurityConfigurerAdapter — 如果没有它,所有路径都将被保护 — 因此用户在尝试访问任何页面时将被重定向到登录页面。 在当前这个示例中,索引页面和登录页面可以在没有身份验证的情况下可以访问。
最后,我们还定义了一个 RequestContextListener bean 来处理请求。
application.yml:
<code class="language-plaintext hljs">server:port: 8082context-path: /uisession:cookie:name: UISESSION
security:basic:enabled: falseoauth2:client:clientId: SampleClientIdclientSecret: secretaccessTokenUri: http://localhost:8081/auth/oauth/tokenuserAuthorizationUri: http://localhost:8081/auth/oauth/authorizeresource:userInfoUri: http://localhost:8081/auth/user/me
spring:thymeleaf:cache: false </code>
有几点需要说明:
我们禁用了默认的 Basic Authentication
accessTokenUri 是获取访问令牌的 URI
userAuthorizationUri 是用户将被重定向到的授权 URI
用户端点 userInfoUri URI 用于获取当前用户的详细信息
另外需要注意,在本例中,我们使用了自己搭建的授权服务器,当然,我们也可以使用其他第三方提供商的授权服务器,例如 Facebook 或 GitHub。
现在来看看客户端应用的前端配置。我们不想把太多时间花费在这里,主要是因为之前已经介绍过了。
客户端应用有一个非常简单的前端:
index.html:
<code class="language-plaintext hljs"><h1>Spring Security SSO</h1>
<a href="securedPage">Login</a> </code>
securedPage.html:
<code class="language-plaintext hljs"><h1>Secured Page</h1>
Welcome, <span th:text="${#authentication.name}">Name</span> </code>
securedPage.html 页面需要用户进行身份验证。 如果未经过身份验证的用户尝试访问 securedPage.html,他们将首先被重定向到登录页面。
现在让我们开始来讨论授权服务器。
首先,在 pom.xml 中定义依赖:
<code class="language-plaintext hljs"><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> </code>
理解我们为什么要在这里将授权服务器和资源服务器作为一个单独的可部署单元一起运行这一点非常重要。
让我们从配置资源服务器开始探讨:
<code class="language-plaintext hljs">@SpringBootApplication
@EnableResourceServer
public class AuthorizationServerApplication extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(AuthorizationServerApplication.class, args);}
} </code>
之后,配置授权服务器:
<code class="language-plaintext hljs">@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate AuthenticationManager authenticationManager;
@Overridepublic void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}
@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("SampleClientId").secret("secret").authorizedGrantTypes("authorization_code").scopes("user_info").autoApprove(true) ; }
@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager);}
} </code>
需要注意的是我们使用 authorization_code 授权类型来开启一个简单的客户端。
首先,我们将通过 application.properties 禁用默认的 Basic Authentication:
<code class="language-plaintext hljs">server.port=8081
server.context-path=/auth
security.basic.enabled=false </code>
现在,让我们到配置定义一个简单的表单登录机制:
<code class="language-plaintext hljs">@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowiredprivate AuthenticationManager authenticationManager;
@Overrideprotected void configure(HttpSecurity http) throws Exception {http.requestMatchers().antMatchers("/login", "/oauth/authorize").and().authorizeRequests().anyRequest().authenticated().and().formLogin().permitAll();}
@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.parentAuthenticationManager(authenticationManager).inMemoryAuthentication().withUser("john").password("123").roles("USER");}
} </code>
请注意,虽然我们使用了简单的内存认证,但可以很简单地将其替换为自定义的 userDetailsService。
最后,我们将创建之前在配置中使用到的用户端点:
<code class="language-plaintext hljs">@RestController
public class UserController {@GetMapping("/user/me")public Principal user(Principal principal) {return principal;}
} </code>
用户数据将以 JSON 形式返回。
在这篇快速教程中,我们使用 Spring Security Oauth2 和 Spring Boot 实现了单点登录。
一如既往,您可以在 GitHub 上找到完整的源码。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。