oauth2.0系统学习3-简单搭建spring sercurity+oauth2.0的框架

三、简单搭建spring sercurity+oauth2.0 的框架

  1. oauth_parent:父工程
  2. oauth-authorizationServer:认证服务器
  3. oauth-ResourceServer:资源服务器

在这里插入图片描述

oauth_parent:父工程代码(就是pom配置)

	<?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>oauth-learn</groupId>
		<artifactId>oauth-parent</artifactId>
		<version>1.0-SNAPSHOT</version>

		<packaging>pom</packaging>

		<parent>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-parent</artifactId>
			<version>2.1.3.RELEASE</version>
		</parent>

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

		<dependencyManagement>
			<dependencies>

				<dependency>
					<groupId>org.springframework.cloud</groupId>
					<artifactId>spring-cloud-dependencies</artifactId>
					<version>Greenwich.RELEASE</version>
					<type>pom</type>
					<scope>import</scope>
				</dependency>


				<dependency>
					<groupId>javax.servlet</groupId>
					<artifactId>javax.servlet-api</artifactId>
					<version>3.1.0</version>
					<scope>provided</scope>
				</dependency>

				<dependency>
					<groupId>javax.interceptor</groupId>
					<artifactId>javax.interceptor-api</artifactId>
					<version>1.2</version>
				</dependency>

				<dependency>
					<groupId>com.alibaba</groupId>
					<artifactId>fastjson</artifactId>
					<version>1.2.47</version>
				</dependency>

				<dependency>
					<groupId>org.projectlombok</groupId>
					<artifactId>lombok</artifactId>
					<version>1.18.0</version>
				</dependency>



				<dependency>
					<groupId>org.springframework.security</groupId>
					<artifactId>spring-security-jwt</artifactId>
					<version>1.0.10.RELEASE</version>
				</dependency>


				<dependency>
					<groupId>org.springframework.security.oauth.boot</groupId>
					<artifactId>spring-security-oauth2-autoconfigure</artifactId>
					<version>2.1.3.RELEASE</version>
				</dependency>


			</dependencies>
		</dependencyManagement>


		<build>

			<plugins>


				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<configuration>
						<source>1.8</source>
						<target>1.8</target>
					</configuration>
				</plugin>

				<plugin>
					<artifactId>maven-resources-plugin</artifactId>
					<configuration>
						<encoding>utf-8</encoding>
						<useDefaultDelimiters>true</useDefaultDelimiters>
					</configuration>
				</plugin>
			</plugins>
		</build>

	</project>

3.1 、搭建一个认证服务器 oauth-authorizationServer

在这里插入图片描述

001)、代码

	package com.feizhou.oauth.bean;

	import lombok.Data;

	/**
	 * 描述该类- JPA
	 *
	 * @author zhoufei
	 * @class: UserBean
	 * @date 2020/10/27 16:09
	 * @Verson 1.0 -2020/10/27 16:09
	 * @see
	 */

	@Data
	public class UserAuthorizeBean {
		private Long id;
		private Long userId;
		private String authorizeCode;
		
	}

	package com.feizhou.oauth.bean;

	import lombok.Data;

	/**
	 * 描述该类- JPA
	 *
	 * @author zhoufei
	 * @class: UserBean
	 * @date 2020/10/27 16:09
	 * @Verson 1.0 -2020/10/27 16:09
	 * @see
	 */

	@Data
	public class UserBean {
		private Long id;
		private String userName;
		private String password;
		
	}

	package com.feizhou.oauth.config;

	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.context.annotation.Bean;
	import org.springframework.context.annotation.Configuration;
	import org.springframework.http.HttpMethod;
	import org.springframework.security.authentication.AuthenticationManager;
	import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
	import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
	import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
	import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
	import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
	import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
	import org.springframework.security.oauth2.provider.ClientDetailsService;
	import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
	import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
	import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
	import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
	import org.springframework.security.oauth2.provider.token.TokenStore;
	import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

	/**
	 * 描述该类- JPA
	 *
	 * @author zhoufei
	 * @class: AuthorizationServer
	 * @date 2020/10/28 21:26
	 * @Verson 1.0 -2020/10/28 21:26
	 * @see
	 */

	@Configuration
	@EnableAuthorizationServer // 配置授权服务。
	public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
		
		// 用来配置客户端详情服务
		@Override
		public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
			// 这里是第三方合作用户的客户id,秘钥的配置
			// 使用in-memory存储
			clients.inMemory()
					// client_id,用户账号
					.withClient("c1")
					// 客户端密钥
					.secret(new BCryptPasswordEncoder().encode("secret"))
					// 资源列表,资源标识
					.resourceIds("res1")
					// 授权类型(4种)
					.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit",
							"refresh_token")
					// 客戶端允许的授权范围
					.scopes("all")
					// false跳转到授权页面,让用户点击授权,如果是true,相当于自动点击授权,就不跳转授权页面
					.autoApprove(false)//
					// 加上验证回调地址,返回授权码信息
					.redirectUris("http://www.baidu.com");
			
			// 如果有多个用户,配置多个客户详情
			// .and().withClient()
			
		}
		
		@Autowired
		// 令牌存储策略
		private TokenStore tokenStore;
		@Autowired
		// 客户端详情服务,也就是configure(ClientDetailsServiceConfigurer clients)方法
		private ClientDetailsService clientDetailsService;
		
		// 令牌管理服务
		@Bean
		public AuthorizationServerTokenServices tokenService() {
			DefaultTokenServices service = new DefaultTokenServices();
			service.setClientDetailsService(clientDetailsService);
			service.setSupportRefreshToken(true);// 支持刷新
			service.setTokenStore(tokenStore);// 令牌存储
			service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
			service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
			return service;
		}
		
		@Autowired
		// 授权码服务
		private AuthorizationCodeServices authorizationCodeServices;
		@Autowired
		// 认证管理
		private AuthenticationManager authenticationManager;
		@Autowired
		// 令牌管理服务
		private AuthorizationServerTokenServices authorizationServerTokenServices;
		
		@Override
		// 用来配置令牌(token)的访问端点
		public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
			endpoints
					// 密码模式需要
					.authenticationManager(authenticationManager)
					// 授权码模式需要
					.authorizationCodeServices(authorizationCodeServices)
					// 令牌管理服务
					.tokenServices(authorizationServerTokenServices).allowedTokenEndpointRequestMethods(HttpMethod.POST);// 允许post提交
		}
		
		@Bean
		// 授权码服务器
		public AuthorizationCodeServices authorizationCodeServices() {
			// 授权码模式的授权码采用内存方式存储
			return new InMemoryAuthorizationCodeServices();
		}
		
		@Override
		// 用来配置令牌端点的安全约束,拦截规则
		public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
			
			security
					// 提供公有密匙的端点,如果你使用JWT令牌的话, 允许
					.tokenKeyAccess("permitAll()")
					// oauth/check_token:用于资源服务访问的令牌解析端点,允许
					.checkTokenAccess("permitAll()")
					// 表单认证,申请令牌
					.allowFormAuthenticationForClients();
		}
		
		@Bean
		// 令牌存储策略
		public TokenStore tokenStore() {
			// 内存存储,普通令牌
			return new InMemoryTokenStore();
		}
	}

	package com.feizhou.oauth.config;

	import org.springframework.context.annotation.Bean;
	import org.springframework.context.annotation.Configuration;
	import org.springframework.security.authentication.AuthenticationManager;
	import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
	import org.springframework.security.config.annotation.web.builders.HttpSecurity;
	import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
	import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
	import org.springframework.security.crypto.password.PasswordEncoder;

	/**
	 * @author Administrator
	 * @version 1.0
	 **/
	@Configuration
	@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
	public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
		
		// 认证管理器
		@Override
		@Bean
		public AuthenticationManager authenticationManagerBean() throws Exception {
			return super.authenticationManagerBean();
		}
		
		// 密码编码器
		@Bean
		public PasswordEncoder passwordEncoder() {
			return new BCryptPasswordEncoder();
		}

		// 安全拦截机制
		@Override
		protected void configure(HttpSecurity http) throws Exception {
			http.
					csrf().disable().

					authorizeRequests().
					antMatchers("/admin/p1").
					hasAnyAuthority("p1").

					antMatchers("/user/p2").
					hasAnyAuthority("p2").
					antMatchers("/login*")
					.permitAll().
					anyRequest().
					authenticated().
					and().
					formLogin();
			
		}
	}

	package com.feizhou.oauth.dao;

	import java.util.ArrayList;
	import java.util.List;

	import com.feizhou.oauth.bean.UserAuthorizeBean;
	import com.feizhou.oauth.bean.UserBean;
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.jdbc.core.BeanPropertyRowMapper;
	import org.springframework.jdbc.core.JdbcTemplate;
	import org.springframework.stereotype.Repository;

	/**
	 * 描述该类- JPA
	 *
	 * @author zhoufei
	 * @class: UserBean
	 * @date 2020/10/27 16:09
	 * @Verson 1.0 -2020/10/27 16:09
	 * @see
	 */

	@Repository
	public class UserDao {
		@Autowired
		JdbcTemplate jdbcTemplate;
		
		// 根据账号查询用户信息
		public UserBean getUserByUsername(String username) {
			String sql = "select * from user where user_name = ?";
			// 连接数据库查询用户
			List<UserBean> list = jdbcTemplate.query(sql, new Object[] { username },
					new BeanPropertyRowMapper<>(UserBean.class));
			if (list != null && list.size() == 1) {
				return list.get(0);
			}
			return null;
		}
		
		// 根据用户id查询用户权限
		public List<String> getAuthorize(Long userId) {
			String sql = "SELECT * FROM user_authorize WHERE user_id =?";
			List<UserAuthorizeBean> list = jdbcTemplate.query(sql, new Object[] { userId },
					new BeanPropertyRowMapper<>(UserAuthorizeBean.class));
			List<String> authorizes = new ArrayList<>();
			list.forEach(c -> authorizes.add(c.getAuthorizeCode()));
			return authorizes;
		}
		
	}

	package com.feizhou.oauth.service;

	import java.util.List;

	import com.feizhou.oauth.bean.UserBean;
	import com.feizhou.oauth.dao.UserDao;
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.security.core.userdetails.User;
	import org.springframework.security.core.userdetails.UserDetails;
	import org.springframework.security.core.userdetails.UserDetailsService;
	import org.springframework.security.core.userdetails.UsernameNotFoundException;
	import org.springframework.stereotype.Service;

	/**
	 * @author Administrator
	 * @version 1.0
	 **/
	@Service
	public class SpringDataUserDetailsService implements UserDetailsService {
		
		@Autowired
		UserDao userDao;
		
		// 根据账号查询用户信息,
		// 通过@Service将SpringDataUserDetailsService注入容器,通过UserDetailsService接口表明该类的类型是UserDetailsService
		@Override
		public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
			
			// 将来连接数据库根据账号查询用户信息
			UserBean bean = userDao.getUserByUsername(username);
			if (bean == null) {
				// 如果用户查不到,返回null,由provider来抛出异常
				return null;
			}
			
			// 查询当前数据库的用户资源权限
			List<String> authorize = userDao.getAuthorize(bean.getId());
			String[] authorizeArr = new String[authorize.size()];
			authorize.toArray(authorizeArr);
			
			// 添加权限
			UserDetails userDetails = User.withUsername(bean.getUserName()).password(bean.getPassword())
					.authorities(authorizeArr).build();
			return userDetails;
		}
	}

application.properties

	spring.application.name=oauth-authorizationServer
	server.port=8081

	spring.datasource.url = jdbc:mysql://zhoufei.ali.db.com:3306/test?useUnicode=true
	spring.datasource.username = root
	spring.datasource.password = root
	spring.datasource.driver-class-name = com.mysql.jdbc.Driver

pom.xml

	<?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">
		<parent>
			<artifactId>oauth-parent</artifactId>
			<groupId>oauth-learn</groupId>
			<version>1.0-SNAPSHOT</version>
		</parent>
		<modelVersion>4.0.0</modelVersion>

		<artifactId>oauth-authorizationServer</artifactId>


		<dependencies>

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


			<dependency>
				<groupId>org.springframework.data</groupId>
				<artifactId>spring-data-commons</artifactId>
			</dependency>

			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-security</artifactId>
			</dependency>

			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-oauth2</artifactId>
			</dependency>

			<dependency>
				<groupId>org.springframework.security</groupId>
				<artifactId>spring-security-jwt</artifactId>
			</dependency>


			<dependency>
				<groupId>mysql</groupId>
				<artifactId>mysql-connector-java</artifactId>
			</dependency>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-jdbc</artifactId>
			</dependency>


			<dependency>
				<groupId>org.projectlombok</groupId>
				<artifactId>lombok</artifactId>
			</dependency>


		</dependencies>


	</project>

002)、理论,解读代码

L1. OAuth2.0授权服务器的开启

  1. @EnableAuthorizationServer注解
  2. 继承AuthorizationServerConfigurerAdapter

在这里插入图片描述

L2. AuthorizationServerConfigurerAdapter:

  1. 要配置以下几个类,通过重写以下方法来实现

    在这里插入图片描述

L3. ClientDetailsServiceConfigurer

  1. 用来配置客户端详情服务(ClientDetailsService )
    1. ClientDetailsService负责查找ClientDetails
  2. 可通过内存或者数据库来配置
  3. 客户端详情服务
    1. 第三方服务器来授权服务器申请访问资源。通过授权后,颁发clientId,secret给第三方服务器,表示第三方服务器是信任的服务器。

ClientDetails重要属性列表:

  1. clientId:标识客户的Id

  2. secret:客户端秘钥

  3. scope:限制客户端的访问范围

    1. 默认空:拥有全部的访问范围。
  4. authorizedGrantTypes:此客户端可以使用的授权类型

    1. 默认为空
  5. authorities:客户端可以使用的权限

    1. 基于SpringSecurityauthorities

ClientDetails介绍

  1. 能够在应用程序运行的时候进行更新
  2. 可以通过访问底层的存储服务
    1. 客户端详情存储在一个关系数据库的表中
    2. 实现方式
      1. 使用JdbcClientDetailsService
      2. 自己实现ClientRegistrationService接口
      3. 自己实现ClientDetailsService接口

具体代码

在这里插入图片描述

L4. AuthorizationServerTokenServices

  1. 令牌管理服务
  2. 定义管理令牌的操作
  3. 令牌
    1. 用来加载身份信息
    2. 包含了这个令牌的相关权限。
  4. 这个接口的实现,则需要继承DefaultTokenServices

在这里插入图片描述

DefaultTokenServices

  1. 可以修改令牌的格式
  2. 可以修改令牌的存储。
  3. 默认的,当它尝试创建一个令牌使用随机值来进行填充的,除了持久化令牌是委托一个TokenStore接口来实现以外,这个类几乎帮你做了所有的事情。

TokenStore

  1. 默认实现:InMemoryTokenStore

    1. 所有的令牌是被保存在了内存中
    2. 它可以完美的工作在单服务器上(即访问并发量压力不大的情况下,并且它在失败的时候不会进行备份)
  2. JdbcTokenStore

    1. 基于JDBC的实现版本,令牌会被保存进关系型数据库
    2. 注意点:需要把"spring-jdbc"这个依赖加入到你的classpath当中。
  3. JwtTokenStore

    1. 它可以把令牌相关的数据进行编码(因此对于后端服务来说,它不需要进行存储,这将是一个重大优势)
    2. 缺点:
      1. 撤销一个已经授权令牌非常困难,所以它通常用来处理一个生命周期较短的令牌以及撤销刷新令牌(refresh_token)
      2. 这个令牌占用的空间会比较大,如果你加入了比较多用户凭证信息。JwtTokenStore不会保存任何数据,但是它在转换令牌值以及授权信息方面与DefaultTokenServices所扮演的角色是一样的。

在这里插入图片描述

L5. AuthorizationServerEndpointsConfigurer

  1. 可以完成令牌服务
  2. 可以完成令牌endpoint配置

配置授权类型(GrantTypes)

  1. authenticationManager:认证管理器
    1. 选择密码(password)授权类型的时候,请设置这个属性注入一个AuthenticationManager对象。
  2. userDetailsService:
    1. 设置UserDetailsService接口的实现类(用户登录验证)
    2. 或者你可以把这个东西设置到全局域上面去(例如GlobalAuthenticationManagerConfigurer这个配置对象),当你设置了这个之后,那么"refresh_token"即刷新令牌授权类型模式的流程中就会包含一个检查,用来确保这个账号是否仍然有效。
  3. authorizationCodeServices:设置授权码服务
    1. 用于"authorization_code"授权码类型模式
  4. implicitGrantService:设置隐式授权模式,用来管理隐式授权模式的状态。
  5. tokenGranter:
    1. 设置TokenGranter接口实现,授权将会交由你来完全掌控,并且会忽略掉上面的这几个属性
    2. 这个属性一般是用作拓展用途的,即标准的四种授权模式已经满足不了你的需求的时候,才会考虑使用这个。

具体代码

在这里插入图片描述

配置授权端点的URL(EndpointURLs)

  1. AuthorizationServerEndpointsConfigurer有一个pathMapping()的方法用来配置端点URL链接
  2. 它有两个参数
    1. 第一个参数:String类型的,这个端点URL的默认链接。
    2. 第二个参数:String类型的,你要进行替代的URL链接。
    3. 以上的参数都将以"/"字符为开始的字符串,
    4. 框架的默认URL链接如下列表,可以作为这个pathMapping()方法的第一个参数
      1. /oauth/authorize:授权端点。
      2. /oauth/token:令牌端点。
      3. /oauth/confirm_access:用户确认授权提交端点。
      4. /oauth/error:授权服务错误信息端点。
      5. /oauth/check_token:用于资源服务访问的令牌解析端点。
      6. /oauth/token_key:提供公有密匙的端点,如果你使用JWT令牌的话。需要注意的是授权端点这个URL应该被SpringSecurity保护起来只供授权用户访问。

L7. authorizationCodeServices

  1. 授权码服务的存储方式

具体代码

在这里插入图片描述


L8. AuthorizationServerSecurityConfigurer

  1. 令牌端点的安全约束

  2. tokenkey:/oauth/token_key端点完全公开。

  3. checkToken:/oauth/check_token端点完全公开。

  4. allowFormAuthenticationForClients:允许表单认证
    具体代码


在这里插入图片描述

3.2 、验证认证服务器

001) 、授权码模式

http://localhost:8081/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com

先让你登录(Security的原因)

在这里插入图片描述

用户授权

在这里插入图片描述

返回授权码

在这里插入图片描述

请求taken

http://localhost:8081/oauth/token?client_id=c1&client_secret=secret&grant_type=authorization_code&code=kZAlHW&redirect_uri=http://www.baidu.com

在这里插入图片描述

002) 、简化模式

http://localhost:8081/oauth/authorize?client_id=c1&response_type=token&scope=all&redirect_uri=http://www.baidu.com

在这里插入图片描述

在这里插入图片描述

003) 、密码模式

http://localhost:8081/oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=admin&password=admin

在这里插入图片描述

004) 、客户端模式

http://localhost:8081/oauth/token?client_id=c1&client_secret=secret&grant_type=client_credentials

在这里插入图片描述

3.3 、搭建一个授权服务器 oauth-authorizationServer

在这里插入图片描述

001)、代码

	package com.feizhou.oauth.config;

	import org.springframework.context.annotation.Bean;
	import org.springframework.context.annotation.Configuration;
	import org.springframework.security.config.annotation.web.builders.HttpSecurity;
	import org.springframework.security.config.http.SessionCreationPolicy;
	import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
	import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
	import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
	import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
	import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;

	/**
	 * @author Administrator
	 * @version 1.0
	 **/
	@Configuration
	@EnableResourceServer
	public class ResouceServerConfig extends ResourceServerConfigurerAdapter {
		
		// 授权服务的资源列表
		public static final String RESOURCE_ID = "res1";
		
		@Override
		public void configure(ResourceServerSecurityConfigurer resources) {
			resources
					// 资源 id
					.resourceId(RESOURCE_ID)
					// 令牌服务
					.tokenServices(tokenService())
					.stateless(true);
		}
		
		@Override
		public void configure(HttpSecurity http) throws Exception {
			
			http
					
					.authorizeRequests().antMatchers("/**")
					// 所有的访问,授权访问都要是all,和认证服务器的授权范围一一对应
					.access("#oauth2.hasScope('all')")
					//去掉防跨域攻击
					.and().csrf().disable()
					//session管理
					.sessionManagement()
					.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
		}
		
		@Bean
		// 资源服务令牌解析服务
		public ResourceServerTokenServices tokenService() {
			// 使用远程服务请求授权服务器校验token,必须指定校验token 的url、client_id,client_secret
			RemoteTokenServices service = new RemoteTokenServices();
			service.setCheckTokenEndpointUrl("http://localhost:8081/oauth/check_token");
			service.setClientId("c1");
			service.setClientSecret("secret");
			return service;
		}
		
	}

	package com.feizhou.oauth.config;

	import org.springframework.context.annotation.Bean;
	import org.springframework.context.annotation.Configuration;
	import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
	import org.springframework.security.config.annotation.web.builders.HttpSecurity;
	import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
	import org.springframework.security.config.http.SessionCreationPolicy;
	import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
	import org.springframework.security.crypto.password.PasswordEncoder;

	//由于Spring boot starter自动装配机制,这里无需使用@EnableWebSecurity
	//@EnableWebSecurity
	@Configuration
	@EnableGlobalMethodSecurity(prePostEnabled = true) // 方法授权
	public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
		
		// 密码编码器,不加密
		@Bean
		public PasswordEncoder passwordEncoder() {
			// return NoOpPasswordEncoder.getInstance(); // 不加密
			return new BCryptPasswordEncoder();// BCryptPasswordEncoder加密
		}
		
		// web url 拦截规则
		@Override
		protected void configure(HttpSecurity http) throws Exception {
			http.authorizeRequests()
					
					.anyRequest().authenticated()// 所有其他请求必须认证通过
					.and().formLogin().loginPage("/login").successForwardUrl("/login-success")// 自定义登录成功的页面地址
					.permitAll().and().logout().permitAll().and()// 会话管理
					.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);// 会话管理
		}
	}

	package com.feizhou.oauth.controller;

	import org.springframework.security.access.prepost.PreAuthorize;
	import org.springframework.security.core.Authentication;
	import org.springframework.security.core.context.SecurityContextHolder;
	import org.springframework.security.core.userdetails.UserDetails;
	import org.springframework.web.bind.annotation.GetMapping;
	import org.springframework.web.bind.annotation.RequestMapping;
	import org.springframework.web.bind.annotation.RestController;

	/**
	 * @author Administrator
	 * @version 1.0
	 **/
	@RestController
	public class LoginController {

		@RequestMapping(value = "/login-success")
		public String loginSuccess() {
			return getUsername() + " login-success 登录成功";
		}

		/**
		 * 测试资源1
		 *
		 * @return
		 */
		@GetMapping(value = "/admin/p1")
		@PreAuthorize("hasAuthority('p1')")//拥有p1权限才可以访问
		public String r1() {
			return " /admin/p1 " + getUsername() + "访问资源1";
		}

		/**
		 * 测试资源2
		 *
		 * @return
		 */
		@GetMapping(value = "/user/p2")
		@PreAuthorize("hasAuthority('p2')")//拥有p2权限才可以访问
		public String r2() {
			return "/user/p2 " + getUsername() + "访问资源2";
		}

		// 获取当前用户信息
		private String getUsername() {
			String username = null;
			// 当前认证通过的用户身份
			Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
			// 用户身份
			Object principal = authentication.getPrincipal();
			if (principal == null) {
				username = "匿名";
			}
			if (principal instanceof UserDetails) {
				UserDetails userDetails = (UserDetails) principal;
				username = userDetails.getUsername();
			} else {
				username = principal.toString();
			}
			return username;
		}
	}

application.properties

	spring.application.name=oauth-ResourceServer
	server.port=8082

pom.xml

	<?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">
		<parent>
			<artifactId>oauth-parent</artifactId>
			<groupId>oauth-learn</groupId>
			<version>1.0-SNAPSHOT</version>
		</parent>
		<modelVersion>4.0.0</modelVersion>

		<artifactId>oauth-ResourceServer</artifactId>

		<dependencies>

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

			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-security</artifactId>
			</dependency>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-oauth2</artifactId>
			</dependency>

			<dependency>
				<groupId>org.projectlombok</groupId>
				<artifactId>lombok</artifactId>
			</dependency>


		</dependencies>
	</project>

002)、代码解读和理论

L1. OAuth2.0资源服务器的开启

  1. @EnableResourceServer注解
    1. 会自动增加了一个类型为OAuth2AuthenticationProcessingFilter的过滤器链
  2. 继承ResourceServerConfigurerAdapter

在这里插入图片描述

L2. ResourceServerSecurityConfigurer

  1. tokenServices:

    1. ResourceServerTokenServices类的实例
    2. 用来实现令牌服务
  2. tokenStore:

    1. TokenStore类的实例,指定令牌如何访问,与tokenServices配置可选
  3. resourceId

    1. 这个资源服务的ID,这个属性是可选的,推荐设置并在授权服务中进行验证
  4. tokenExtractor

    1. 令牌提取器用来提取请求中的令牌

在这里插入图片描述

L3. HttpSecurity配置这个与Spring Security类似

在这里插入图片描述

L4. ResourceServerTokenServices

  1. DefaultTokenServices

    1. 授权服务和资源服务在同一个应用程序上可以使用
    2. 在资源服务器本地配置令牌存储、解码、解析方式使用
  2. RemoteTokenServices

    1. 资源服务器通过HTTP请求来解码令牌
    2. 请求端点:/oauth/check_token

在这里插入图片描述

003)、测试

获取token

在这里插入图片描述

检查token的信息

在这里插入图片描述

admin请求可以访问的资源

在这里插入图片描述

user请求可以访问的资源(token 是admin的)

在这里插入图片描述

代码文章
https://gitee.com/DanShenGuiZu/learnDemo/tree/mysql_mybaties_DB/oauth2.0-learn

©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页