SSO即Single Sign-On,单点登录,即授权服务器形式,通过在一个网站上登录完后,给予过授权的就可以直接用这个帐号信息登录了,类似于qq微信登录其他APP。
本篇文章,将利用Spring Security实现简单的单点登录中需要的,认证服务器和客户端。
原文链接:http://www.baeldung.com/sso-spring-security-oauth2
SSO服务器
首先实现一个SSO服务器,下面是基本的pom文件:
<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>
启动main方法:
这里面主要用EnableResourceServer来开启资源服务器。
@SpringBootApplication
@EnableResourceServer
public class SsoServerApplication {
public static void main(String[] args) {
SpringApplication.run(SsoServerApplication.class, args);
}
}
下面再分别介绍Spring Security和OAuth2的Config类:
以下是OAuth2的Config类:
//Auth2的配置文件
@Configuration
@EnableAuthorizationServer
public class Auth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager; //使用默认的认证管家
@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()") //能够获取token的
.checkTokenAccess("isAuthenticated()"); //检测是否认证
}
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("SampleClientId") //接受的clientId
.secret("secret") //默认secret
.authorizedGrantTypes("authorization_code") //授权模式
.scopes("user_info") //范围,只获取用户认证。
.autoApprove(true);
}
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
}
Auth2Config
定义了一些Auth2的信息,例如对名为SampleClientId
的注册,以及对认证规则的定义:
oauthServer.tokenKeyAccess("permitAll()") //能够获取token的
.checkTokenAccess("isAuthenticated()"); //检测是否认证
以下是Spring Security的配置:
@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 { // @formatter:off
auth.parentAuthenticationManager(authenticationManager)
.inMemoryAuthentication()
.withUser("anla7856") //模拟一个注册用户名
.password("123456")
.roles("USER");
}
}
下面是application.yml配置:
server:
port: 8080
context-path: /auth
security:
basic:
enabled: false #阻止基本认证
下面是sso客户端代码:
SSO客户端
sso客户端,也是基于Spring Security实现,下面是其pom文件:
<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>
再看看启动Application类:
@SpringBootApplication
public class SsoClientApplication {
@Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
} //自定义一个RequestContextListener
public static void main(String[] args) {
SpringApplication.run(SsoClientApplication.class, args);
}
}
接下来是Spring Security的配置文件:
@EnableOAuth2Sso
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**")
.permitAll()
.anyRequest()
.authenticated();
}
}
下面是 WebMvcConfig:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Override
public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
configurer.enable(); //使配置生效
}
/**
* 配置view
* @param registry
*/
@Override
public void addViewControllers(final ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/")
.setViewName("forward:/index");
registry.addViewController("/index");
registry.addViewController("/securedPage");
}
/**
* 映射资源文件
* @param registry
*/
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
application.yml文件:
server:
port: 8989
session:
cookie:
name: UI2SESSION
security:
basic:
enabled: false
oauth2:
client:
clientId: SampleClientId #与server端对应
clientSecret: secret #与服务端对应
accessTokenUri: http://localhost:8080/auth/oauth/token
userAuthorizationUri: http://localhost:8080/auth/oauth/authorize
resource:
userInfoUri: http://localhost:8080/auth/door/me #资源服务器,即对sso server的资源访问。
spring:
thymeleaf:
cache: false
整体的架构也算搭好了,server端和client端都是用Spring Security,当用户访问client的页面时,由Spring Security控制,会使其跳转到sso Server端的默认login页面进行验证,也就是在Server端配置好的clientid,当验证用户名密码通过时,返回给给客户端,此时客户端从security.oauth2.resource.userInfoUri的资源服务器下获取相应的资源。
代码在hello-springcloud 下的v6分支。
参考资料:
1. http://www.baeldung.com/sso-spring-security-oauth2
2. https://projects.spring.io/spring-security-oauth/docs/oauth2.html
3. https://spring.io/projects/spring-security
4. http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
5. https://blog.csdn.net/xiejx618/article/details/51039653