oauth2.0--基础--03--简单搭建认证服务器,资源服务器

oauth2.0–基础–03–简单搭建认证服务器,资源服务器


代码文章

https://gitee.com/DanShenGuiZu/learnDemo/tree/master/auth2.0--learn/simple-auth2.0/oauth_parent

1、整体代码

  1. 框架:spring sercurity+oauth2.0

1.1、代码结构

在这里插入图片描述

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

2、oauth_parent:父工程代码

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">
    <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、认证服务器代码:oauth-authorizationServer

在这里插入图片描述

3.1、代码

UserAuthorizeBean


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;
	
}

UserBean

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;
	
}

AuthorizationServer


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();
	}
}

WebSecurityConfig


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();
		
	}
}

UserDao


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;
	}
	
}


SpringDataUserDetailsService


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>



mysql.sql

数据库脚本

 
CREATE TABLE `user` (
    `id` bigint(255) NOT NULL AUTO_INCREMENT,
    `password` varchar(255) DEFAULT NULL,
    `user_name` varchar(255) DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

CREATE TABLE `user_authorize` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) DEFAULT NULL,
  `authorize_code` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

INSERT INTO  `user_authorize`(`id`, `user_id`, `authorize_code`) VALUES (1, 1, 'admin');
-- 账号密码都是admin
INSERT INTO  `user`(`id`, `password`, `user_name`) VALUES (1, '$2a$10$4ewqeeIzvg4rBIIvSC4QFu4DEO0xGcHetdjac4950UbOX91Jrk1we', 'admin');


3.2、解读代码

3.2.1、OAuth2.0授权服务器的开启

  1. 使用 @EnableAuthorizationServer注解
  2. 继承 AuthorizationServerConfigurerAdapter

在这里插入图片描述

3.2.2、AuthorizationServerConfigurerAdapter:

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

在这里插入图片描述

3.2.3、ClientDetailsServiceConfigurer

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

ClientDetails重要属性列表:

  1. clientId:标识客户的Id
  2. secret:客户端秘钥
  3. scope:
    1. 限制客户端的访问范围
    2. 默认空:拥有全部的访问范围。
  4. authorizedGrantTypes:
    1. 客户端可以使用的授权类型
    2. 默认为空
  5. authorities:
    1. 客户端可以使用的权限
    2. 基于SpringSecurityauthorities

ClientDetails介绍

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

具体代码

在这里插入图片描述

3.2.4、AuthorizationServerTokenServices

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

在这里插入图片描述

DefaultTokenServices

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

TokenStore

  1. 默认实现:InMemoryTokenStore
    1. 所有的令牌是被保存在了内存中
    2. 它可以完美的工作在单服务器上(即访问并发量压力不大的情况下,并且它在失败的时候不会进行备份)
  2. JdbcTokenStore
    1. 基于JDBC的实现版本,令牌会被保存进关系型数据库
    2. 注意点:需要把"spring-jdbc"这个依赖加入到你的classpath当中。
  3. JwtTokenStore
    1. 它可以把令牌相关的数据进行编码(因此对于后端服务来说,它不需要进行存储,这将是一个重大优势)
    2. 缺点:
      1. 撤销一个已经授权令牌非常困难,所以它通常用来处理一个生命周期较短的令牌以及撤销刷新令牌(refresh_token)
      2. 这个令牌占用的空间会比较大,如果你加入了比较多用户凭证信息。JwtTokenStore不会保存任何数据,但是它在转换令牌值以及授权信息方面与DefaultTokenServices所扮演的角色是一样的。

在这里插入图片描述

3.2.5、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保护起来只供授权用户访问。

3.2.6、authorizationCodeServices

授权码服务的存储方式

具体代码

在这里插入图片描述


3.2.7、AuthorizationServerSecurityConfigurer

  1. 令牌端点的安全约束
  2. tokenkey:/oauth/token_key端点完全公开。
  3. checkToken:/oauth/check_token端点完全公开。
  4. allowFormAuthenticationForClients:允许表单认证

具体代码

在这里插入图片描述

3.3、验证认证服务器

3.3.1、授权码模式

01、请求授权码
http://localhost:8081/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com
02、先让你登录(Security的原因)

在这里插入图片描述

02、用户授权

在这里插入图片描述

03、返回授权码

在这里插入图片描述

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

在这里插入图片描述

3.3.2、简化模式

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

在这里插入图片描述

在这里插入图片描述

3.3.3、密码模式

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

在这里插入图片描述

3.3.4、客户端模式


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

在这里插入图片描述

4、资源服务器代码:oauth-ResourceServer

在这里插入图片描述

4.1、代码

ResouceServerConfig

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;
	}
	
}

ResouceServerConfig

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);// 会话管理
	}
}

LoginController


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>

4.2、代码解读

4.2.1、OAuth2.0资源服务器的开启

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

在这里插入图片描述

4.2.2、ResourceServerSecurityConfigurer

  1. tokenServices:
    1. ResourceServerTokenServices 类的实例
    2. 用来实现令牌服务
  2. tokenStore:
    1. TokenStore类的实例,指定令牌如何访问,与tokenServices配置可选
  3. resourceId
    1. 这个资源服务的ID,这个属性是可选的,推荐设置并在授权服务中进行验
  4. tokenExtractor
    1. 令牌提取器用来提取请求中的令牌

在这里插入图片描述

4.2.3、HttpSecurity配置这个与Spring Security类似

在这里插入图片描述

4.2.4、ResourceServerTokenServices

  1. DefaultTokenServices
    1. 授权服务和资源服务在同一个应用程序上可以使用
    2. 在资源服务器本地配置令牌存储、解码、解析方式使用
  2. RemoteTokenServices
    1. 资源服务器通过HTTP请求来解码令牌
    2. 请求端点:/oauth/check_token

在这里插入图片描述

4.3、测试

01、获取token

在这里插入图片描述

02、检查token的信息

在这里插入图片描述

03、admin请求可以访问的资源

在这里插入图片描述

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

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值