Spring security Oauth2.0 SSO单点登录实现 Securty 简单讲解

   因为公司的项目需要一个新开发的单点登录系统,以前从没有接触过登录安全方面的,然后最近这段时间充电学习使用Oauth2.0完成登录和授权,也是在学习完成之后项目搭建好之后写了这篇博客,用来记录学习的收获。

  Oauth2.0协议,相信有需要使用的小伙伴们都已经了解过了,我就不赘述了,下面直接开始单点登录系统的搭建。

 

首先在Spring io上面下载一个Spring boot项目,基于Spring boot的注解能快速的实现我们想要的单点登录,在代码中我会插入一些自己对Spring Sucurity的理解。

    

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.oauthDemo</groupId>
	<artifactId>oauth</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>oauth</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<mysql.vsrsion>6.0.6</mysql.vsrsion>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</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>
			<version>2.0.14.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<!--Druid数据源-->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.19</version>
		</dependency>
		<!--MySql驱动-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.vsrsion}</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

 

  这是在项目中需要的依赖。

  在这里我们首先讲一个Spring Security的安全验证流程,Spring Security 实现登录和授权实际上是使用的一个过滤器链

  图片是百度Spring Security 过滤器链找到的,我加入了一点自己的理解,将过滤器链简单的归纳一下,让使用者对Spring Security的认证流程有一个简单的概念。

 

  SecurityContextPersistenceFilter:

  在浏览器发起一个请求的时候第一个经过的过滤器,这个过滤器实现的功能是,如果当前的请求中有经过认证的用户信息,就取出来,如果没有经过

用户的认证信息就把自身的存储的用户信息放进去,如果没有用户信息就直接通过。

  FilterSecurityInterceptor:

   从请求中获取认证信息,如果有认证的信息就会放行,如果请求中没有认证过的用户信息,就会抛一个异常,而它左边的ExceptionTranslationFilter 就是捕获整个过滤器链的异常,然后进行不同的操作,如果在FilterSecurityInterceptor 捕获的异常是用户未认证的异常,他就会根据Security的配置引导用户去到登录页面去进行登录操作。

  UsernamePasswordAuthenticationFilter :

  处理来自表单登录的请求,表单必须提供用户名和密码,在配置中,用户还能自己重写登录成功或者失败的Handler方法,来自定义登录成功和失败的处理,在这个过滤器中,会生成一个UsernamePasswordAuthenticationToken这个对象是一个未经过认证的token对象。这个对象中有两个构造方法,一个构造方法是生成未经过认证的token对象,一个是认证完成之后的生成经过认证的token对象。

  BasicAuthenticationFilter:

  这个过滤器和上一个表单的过滤器是一起的,只不过这个是过滤Basic登录请求的。

  RememberMeAuthenticationFiter:

  看前面就能理解这个过滤器的作用,记住我,当登录的表单有记住我这个勾选框,并且这个勾选框的nane要和Spring Security所指定的name一致,在用户登录成功后,这个过滤器就会在浏览器保存一个Cookie,并且在数据表中存储一个token信息和对应的用户名信息,下次打开的时候会先进入这个过滤器,如果浏览器有token的登录信息,并且和数据库中存储的信息对应就会默认是当前这个用户登录,会自动走一遍认证的流程,如果用户正常,不是异常状态,就可以免登陆,实现RememberMe记住我。

  

   上面介绍的几个是Spring Security默认提供的过滤器链,上图中RememberMeAuthenticationFiter下面的过滤器是其他的登录方式的过滤器,但是实际上和表单登录的逻辑是一样,只不过在这样的过滤器中实现的是我们自己定义的登录逻辑。

   经过上面对Security的认证流程简单认知后,我们开始来构建一个简单的授权登录的Oauthor2.0认证服务器。

  

  首先我们在项目目录下新建一个Class,用来当做Security的配置类,虽然Security有默认的配置类,但是如果我们要实现我们自己的逻辑,就必须要自己来配置一些信息。

  

@Configuration
public class webSecurityConfig extends WebSecurityConfigurerAdapter {

    // 查询用户的实现类
    @Autowired
    private UserDetailsService UserServiceImpl;
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(UserServiceImpl).passwordEncoder(new BCryptPasswordEncoder()); } /** * 功能描述: 如果其他地方想要注入AuthenticationManager的话,这里必须要声明这个Bean */ @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } /** * 这是Security的安全认证策略,默认的是所有请求都可以在授权之后访问 */ @Override protected void configure(HttpSecurity http) throws Exception { http .formLogin() .and() .authorizeRequests() .anyRequest() .authenticated(); } }

 

 

  这是一个非常简单的访问配置,意思是 使用表单登录,所有的请求,都需要经过认证之后才能访问。

  实现的UserDetailsService是Security提供给我们的接口,让我们来自定义用户的登录逻辑。

  

/**
 * @author  by stephen
 * @date  2018/10/18.
 */
@Service
public class UserServiceImpl implements UserDetailsService {

    /**
     *
     * 功能描述: 实现Security中的从数据库中查询对象,这里可以引入操作数据库对象的方式,然后来从数据库中根据用户名
     * 获取你自己的用户对象,然后返回一个Security的UserDetails对象
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return new User("user","123456",new ArrayList<>());
    }
}

  到这里,简单的Seucirty配置就配置完成了。

  接下来就是Oauth2.0的配置,oauth2.0的配置和Sercurity配置类似,但是需要自己在项目中指定Mysql依赖和配置数据源,这里我就不将数据源的信息贴出来了,使用Oauth2.0在数据库中保存信息的话需要自己新建三张表,这三张表可以百度一下然后自己了解一下。

 

@Configuration
@EnableAuthorizationServer
public class authorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    /**
     *  数据源信息
     */
    @Autowired
    private DataSource dataSource;
    @Autowired
    private TokenStore tokenStore;
    /**
     *  声明TokenStore实现
     */
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    /**
     * 声明 ClientDetails实现,这里有封装方法进过数据源验证请求提交的数据
     */
    @Bean
    public ClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }


    /**
     * oauth2认证的客户端信息,连接的客户端必须要在oauth2中注册过
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService UserServiceImpl;

    @Autowired
    private ClientDetailsService clientDetails;

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setTokenStore(tokenStore);
        return tokenServices;
    }

    /**
     * 该方法是用来配置Authorization Server endpoints的一些非安全特性的,比如token存储、token自定义、授权类型等等的
     * 默认情况下,你不需要做任何事情,除非你需要密码授权,那么在这种情况下你需要提供一个AuthenticationManager
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        endpoints.tokenStore(tokenStore());
        endpoints.userDetailsService(UserServiceImpl);
        endpoints.setClientDetailsService(clientDetails);
        endpoints.tokenServices(tokenServices());
        //配置TokenServices参数
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(endpoints.getTokenStore());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
        tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toHours(1));
    }
}
authorizationServerConfiguration

  最后还要加上资源服务器的配置,这次我们将资源服务器和认证服务器部署在一个项目内,正常来说是需要分开配置的。

@Configuration
@EnableResourceServer
public class resourceServerConfiguration extends ResourceServerConfigurerAdapter {

    /**
     * 资源服务器与授权服务器为一体,此处配置守保护的资源
     * @param http
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().antMatchers("/user/**")
                .and()
                .authorizeRequests()
                .anyRequest().authenticated();
    }
}

到这里配置就差不多了,我们可以启动项目测试一下。

 首先,我们在Spring boot 的启动类上做一点改造

@SpringBootApplication
@RestController
public class OauthApplication {

    @RequestMapping("/Hello")
    public String HelloOauth(){
        return "成功!";
    }

    public static void main(String[] args) {
        SpringApplication.run(OauthApplication.class, args);
    }
}

然后启动项目,我们访问这个Hello这个地址

 

 Spring Security会自动为我们跳转到登录界面,我们在这个登录界面来输入我们在UserDetailsService中的创建的User对象的用户名和密码点击登录。

 

 

 

  他会自动帮我们跳会我们之前请求的地址,但是实际上我们的这些功能,Spring Security就可以实现了,接下来,我们来搭建两个项目,在这两个项目之间实现单点登录的效果。

 

  在Spring io上面再次导出两个新的项目,加入如下的依赖

  

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

  客户端的配置其实相当渐变,我们只需要在Application上面加上单点登录的注解,然后让这个启动类可以被访问,来测试一下我们的单点登录

 这是客户端A的

@SpringBootApplication
@EnableOAuth2Sso
@RestController
public class OauthApplication {
    @RequestMapping("/findA")
    public String find(){
        return "Aaaaaaaaaa";
    }

    public static void main(String[] args) {
        SpringApplication.run(OauthApplication.class, args);
    }
}

这是客户端B的

@SpringBootApplication
@EnableOAuth2Sso
@RestController
public class OauthApplication {
    @RequestMapping("/findB")
    public String find(){
        return "BBBBBB";
    }

    public static void main(String[] args) {
        SpringApplication.run(OauthApplication.class, args);
    }
}

然后我们启动之后请求就可以来测试一下是否可以单点登录了

访问A和B都会跳转到认证服务器的登录页面,我们登录其中一个页面:

然后我们返回第一个选项卡的位置,这是请求A的地址,我们重新请求一下A

请求都通过了认证。

到此我们简单的单点登录就完成了。

 

转载于:https://www.cnblogs.com/Yye0118/p/9994624.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值