OAuth 2.0
是介于 用户资源 和 第三方应用 之间的一个 中间层 ,它把 资源 和 第三方应用 隔开,使得 第三方应用 无法直接访问 资源 ,从而起到 保护资源 的作用。为了访问这种 受限资源 , 第三方应用 (客户端)在访问的时候需要 提供凭证 。
在 认证 与 授权 的过程中,主要包含以下 3
种角色:
服务提供方: Authorization Server
资源持有者: Resource Server
客户端: Client
OAuth 2.0
的 认证流程 如图所示,具体如下:
用户( 资源持有者 )打开 客户端 , 客户端 询问 用户授权 。
用户同意授权。
客户端向 授权服务器 申请授权。
授权服务器对 客户端 进行认证,也包括 用户信息 的认证,认证成功后授权给予 令牌 。
客户端获取令牌后, 携带令牌 向 资源服务器 请求资源。
资源服务器确认令牌正确无误,向 客户端 发放资源。
OAuth2 Provider
的角色被分为 Authorization Server
( 授权服务 )和 Resource Service
( 资源服务 ),通常它们不在同一个服务中,可能一个 Authorization Service
对应 多个 Resource Service
。 Spring OAuth2.0
需配合 Spring Security
一起使用,所有的请求由 Spring MVC
控制器处理,并经过一系列的 Spring Security
过滤器拦截。
在 Spring Security
过滤器链 中有以下两个 端点 ,这两个节点用于从 Authorization Service
获取验证 和 授权 。
用于 授权 的端点:默认为 /oauth/authorize
。
用于获取 令牌 的端点:默认为 /oauth/token
。
客户端信息可以存储在 数据库 中,这样就可以通过更改 数据库 来实时 更新客户端信息 的数据。 Spring OAuth2
已经设计好了数据库的表,且不可变。首先将以下 DDL
导入数据库中。
SET NAMES utf8; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for `clientdetails` -- ---------------------------- DROP TABLE IF EXISTS `clientdetails`; CREATE TABLE `clientdetails` ( `appId` varchar(128) NOT NULL, `resourceIds` varchar(256) DEFAULT NULL, `appSecret` varchar(256) DEFAULT NULL, `scope` varchar(256) DEFAULT NULL, `grantTypes` varchar(256) DEFAULT NULL, `redirectUrl` varchar(256) DEFAULT NULL, `authorities` varchar(256) DEFAULT NULL, `access_token_validity` int(11) DEFAULT NULL, `refresh_token_validity` int(11) DEFAULT NULL, `additionalInformation` varchar(4096) DEFAULT NULL, `autoApproveScopes` varchar(256) DEFAULT NULL, PRIMARY KEY (`appId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `oauth_access_token` -- ---------------------------- DROP TABLE IF EXISTS `oauth_access_token`; CREATE TABLE `oauth_access_token` ( `token_id` varchar(256) DEFAULT NULL, `token` blob, `authentication_id` varchar(128) NOT NULL, `user_name` varchar(256) DEFAULT NULL, `client_id` varchar(256) DEFAULT NULL, `authentication` blob, `refresh_token` varchar(256) DEFAULT NULL, PRIMARY KEY (`authentication_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `oauth_approvals` -- ---------------------------- DROP TABLE IF EXISTS `oauth_approvals`; CREATE TABLE `oauth_approvals` ( `userId` varchar(256) DEFAULT NULL, `clientId` varchar(256) DEFAULT NULL, `scope` varchar(256) DEFAULT NULL, `status` varchar(10) DEFAULT NULL, `expiresAt` datetime DEFAULT NULL, `lastModifiedAt` datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `oauth_client_details` -- ---------------------------- DROP TABLE IF EXISTS `oauth_client_details`; CREATE TABLE `oauth_client_details` ( `client_id` varchar(256) NOT NULL, `resource_ids` varchar(256) DEFAULT NULL, `client_secret` varchar(256) DEFAULT NULL, `scope` varchar(256) DEFAULT NULL, `authorized_grant_types` varchar(256) DEFAULT NULL, `web_server_redirect_uri` varchar(256) DEFAULT NULL, `authorities` varchar(256) DEFAULT NULL, `access_token_validity` int(11) DEFAULT NULL, `refresh_token_validity` int(11) DEFAULT NULL, `additional_information` varchar(4096) DEFAULT NULL, `autoapprove` varchar(256) DEFAULT NULL, PRIMARY KEY (`client_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `oauth_client_token` -- ---------------------------- DROP TABLE IF EXISTS `oauth_client_token`; CREATE TABLE `oauth_client_token` ( `token_id` varchar(256) DEFAULT NULL, `token` blob, `authentication_id` varchar(128) NOT NULL, `user_name` varchar(256) DEFAULT NULL, `client_id` varchar(256) DEFAULT NULL, PRIMARY KEY (`authentication_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `oauth_code` -- ---------------------------- DROP TABLE IF EXISTS `oauth_code`; CREATE TABLE `oauth_code` ( `code` varchar(256) DEFAULT NULL, `authentication` blob ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `oauth_refresh_token` -- ---------------------------- DROP TABLE IF EXISTS `oauth_refresh_token`; CREATE TABLE `oauth_refresh_token` ( `token_id` varchar(256) DEFAULT NULL, `token` blob, `authentication` blob ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `role` -- ---------------------------- DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `user` -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `password` varchar(255) DEFAULT NULL, `username` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `UK_sb8bbouer5wak8vyiiy4pf2bx` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `user_role` -- ---------------------------- DROP TABLE IF EXISTS `user_role`; CREATE TABLE `user_role` ( `user_id` bigint(20) NOT NULL, `role_id` bigint(20) NOT NULL, KEY `FKa68196081fvovjhkek5m97n3y` (`role_id`), KEY `FK859n2jvi8ivhui0rl0esws6o` (`user_id`), CONSTRAINT `FK859n2jvi8ivhui0rl0esws6o` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`), CONSTRAINT `FKa68196081fvovjhkek5m97n3y` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; SET FOREIGN_KEY_CHECKS = 1; 复制代码
采用 Maven
的多 Module
的项目结构,新建一个 空白的 Maven
工程,并在 根目录 的 pom.xml
文件中配置 Spring Boot
的版本 1.5.3.RELEASE
, Spring Cloud
的版本为 Dalston.RELEASE
,完整的代码如下:
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> <relativePath/> </parent> <modules> <module>eureka-server</module> <module>service-auth</module> <module>service-hi</module> </modules> <groupId>io.github.ostenant.springcloud</groupId> <artifactId>spring-cloud-oauth2-example</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-cloud-oauth2-example</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Dalston.RELEASE</spring-cloud.version> </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> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 复制代码
新建一个 eureka-server
模块,并添加 Eureka
的相关依赖,并指定 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>io.github.ostenant.springcloud</groupId> <artifactId>eureka-server</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>eureka-server</name> <description>Demo project for Spring Boot</description> <parent> <groupId>io.github.ostenant.springcloud</groupId> <artifactId>spring-cloud-oauth2-example</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 复制代码
在 eureka-server
模块的配置文件 application.yml
中配置 Eureka Server
的信息:
server: port: 8761 eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 复制代码
最后在应用的 启动类 上添加 @EnableEurekaServer
注解开启 Eureka Server
的功能。
@EnableEurekaServer @SpringBootApplication public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } 复制代码
新建一个 service-auth
模块,并添加以下依赖,作为 Uaa
( 授权服务 ),完整的代码如下:
<?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>io.github.ostenant.springcloud</groupId> <artifactId>service-auth</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>service-auth</name> <description>Demo project for Spring Boot</description> <parent> <groupId>io.github.ostenant.springcloud</groupId> <artifactId>spring-cloud-oauth2-example</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 复制代码
打开 spring-cloud-starter-oauth2
依赖包可以看到,它已经整合了以下 3
个 起步依赖 :
spring-cloud-starter-security
spring-security-oauth2
spring-security-jwt
在 service-oauth
模块中的 application.yml
完成如下配置:
spring: application: name: service-auth datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/spring-cloud-auth?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8 username: root password: 123456 jpa: hibernate: ddl-auto: update show-sql: true server: context-path: /uaa port: 5000 security: oauth2: resource: filter-order: 3 # basic: # enabled: false eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ 复制代码
配置 security.oauth2.resource.filter-order
为 3
,在 Spring Boot 1.5.x
版本之前,可以省略此配置。
由于 auth-service
需要对外暴露检查 Token
的 API
接口,所以 auth-service
其实也是一个 资源服务 ,需要在 auth-service
中引入 Spring Security
,并完成相关配置,从而对 auth-service
的 资源 进行保护。
WebSecurityConfig.java
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserServiceDetail userServiceDetail; @Override protected void configure(HttpSecurity http) throws Exception { // @formatter:off http.authorizeRequests().anyRequest().authenticated() .and() .csrf().disable(); // @formatter:on } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userServiceDetail).passwordEncoder(new BCryptPasswordEncoder()); } @Override public @Bean AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } 复制代码
UserServiceDetail.java
@Service public class UserServiceDetail implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userRepository.findByUsername(username); } } 复制代码
配置表的关系映射类 User
,需要实现 UserDetails
接口:
@Entity public class User implements UserDetails, Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String username; @Column private String password; @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")) private List<Role> authorities; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } // setter getter @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } } 复制代码
配置表的关系映射类 Role
,需要实现 GrantedAuthority
接口:
@Entity public class Role implements GrantedAuthority { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; // setter getter @Override public String getAuthority() { return name; } @Override public String toString() { return name; } } 复制代码
UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); } 复制代码
配置 认证服务器 ,使用 @EnableAuthorizationServer
注解开启 Authorization Server
,对外提供 认证 和 授权 的功能。
@Configuration @EnableAuthorizationServer public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter { // 将Token存储在内存中 // private TokenStore tokenStore = new InMemoryTokenStore(); private TokenStore tokenStore = new JdbcTokenStore(dataSource); @Autowired @Qualifier("dataSource") private DataSource dataSource; @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Autowired private UserServiceDetail userServiceDetail; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // 将客户端的信息存储在内存中 clients.inMemory() // 创建了一个client名为browser的客户端 .withClient("browser") // 配置验证类型 .authorizedGrantTypes("refresh_token", "password") // 配置客户端域为“ui” .scopes("ui") .and() .withClient("service-hi") .secret("123456") .authorizedGrantTypes("client_credentials", "refresh_token","password") .scopes("server"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // 配置Token的存储方式 endpoints.tokenStore(tokenStore) // 注入WebSecurityConfig配置的bean .authenticationManager(authenticationManager) // 读取用户的验证信息 .userDetailsService(userServiceDetail); } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { // 对获取Token的请求不再拦截 oauthServer.tokenKeyAccess("permitAll()") // 验证获取Token的验证信息 .checkTokenAccess("isAuthenticated()"); } } 复制代码
在应用的启动类上,使用 @EnableResourceServer
注解 开启资源服务 ,应用需要对外暴露获取 token
的 API
接口。
@EnableEurekaClient @EnableResourceServer @SpringBootApplication public class ServiceAuthApplication { public static void main(String[] args) { SpringApplication.run(ServiceAuthApplication.class, args); } } 复制代码
本例采用 RemoteTokenService
这种方式对 token
进行 验证 。如果 其他资源服务 需要验证 token
,则需要远程调用 授权服务 暴露的 验证 token
的 API
接口。
@RestController @RequestMapping("/users") public class UserController { @RequestMapping(value = "/current", method = RequestMethod.GET) public Principal getUser(Principal principal) { return principal; } } 复制代码
新建一个 service-hi
模块,这个服务作为 资源服务 。在 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>io.github.ostenant.springcloud</groupId> <artifactId>service-hi</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>service-hi</name> <description>Demo project for Spring Boot</description> <parent> <groupId>io.github.ostenant.springcloud</groupId> <artifactId>spring-cloud-oauth2-example</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 复制代码
在 application.yml
中配置 service-hi
在 service-auth
中配置的 OAuth Client
信息:
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8762 spring: application: name: service-hi datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/spring-cloud-auth?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8 username: root password: 123456 jpa: hibernate: ddl-auto: update show-sql: true security: oauth2: resource: user-info-uri: http://localhost:5000/uaa/users/current #获取当前Token的用户信息 client: clientId: service-hi clientSecret: 123456 accessTokenUri: http://localhost:5000/uaa/oauth/token #获取Token grant-type: client_credentials,password scope: server 复制代码
server-hi
模块作为 Resource Server
( 资源服务 ),需要进行 Resource Server
的相关配置,配置代码如下:
@Configuration @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true) public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 对用户注册的URL地址开放 .antMatchers("/user/registry").permitAll() .anyRequest().authenticated(); } } 复制代码
@Configuration @EnableOAuth2Client @EnableConfigurationProperties public class OAuth2ClientConfig { @Bean @ConfigurationProperties(prefix = "security.oauth2.client") public ClientCredentialsResourceDetails clientCredentialsResourceDetails() { // 配置受保护资源的信息 return new ClientCredentialsResourceDetails(); } @Bean public RequestInterceptor oauth2FeignRequestInterceptor(){ // 配置一个拦截器,对于每一个外来的请求,都会在request域内创建一个AccessTokenRequest类型的bean。 return new OAuth2FeignRequestInterceptor( new DefaultOAuth2ClientContext(), clientCredentialsResourceDetails()); } @Bean public OAuth2RestTemplate clientCredentialsRestTemplate() { // 用于向认证服务器服务请求token return new OAuth2RestTemplate(clientCredentialsResourceDetails()); } } 复制代码
把 service-auth
模块的 User.java
和 UserRepository.java
拷贝到 service-hi
模块中。创建 UserService
用于 创建用户 ,并对 用户密码 进行 加密 。
UserService.java
@Service public class UserService { private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); @Autowired private UserRepository userRepository; public User create(String username, String password) { User user = new User(); user.setUsername(username); String hash = encoder.encode(password); user.setPassword(hash); return userRepository.save(user); } } 复制代码
UserController.java
@RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @RequestMapping(value = "/registry", method = RequestMethod.POST) public User createUser(@RequestParam("username") String username, @RequestParam("password") String password) { return userService.create(username,password); } } 复制代码
@RestController public class HiController { private static final Logger LOGGER = LoggerFactory.getLogger(HiController.class); @Value("${server.port}") private String port; /** * 不需要任何权限,只要Header中的Token正确即可 */ @RequestMapping("/hi") public String hi() { return "hi : " + ",i am from port: " + port; } /** * 需要ROLE_ADMIN权限 */ @PreAuthorize("hasAuthority('ROLE_ADMIN')") @RequestMapping("/hello") public String hello() { return "hello you!"; } /** * 获取当前认证用户的信息 */ @GetMapping("/getPrinciple") public OAuth2Authentication getPrinciple(OAuth2Authentication oAuth2Authentication, Principal principal, Authentication authentication){ LOGGER.info(oAuth2Authentication.getUserAuthentication().getAuthorities().toString()); LOGGER.info(oAuth2Authentication.toString()); LOGGER.info("principal.toString()" + principal.toString()); LOGGER.info("principal.getName()" + principal.getName()); LOGGER.info("authentication:" + authentication.getAuthorities().toString()); return oAuth2Authentication; } } 复制代码
@EnableEurekaClient @SpringBootApplication public class ServiceHiApplication { public static void main(String[] args) { SpringApplication.run(ServiceHiApplication.class, args); } } 复制代码
依次启动 eureka-service
, service-auth
和 service-hi
三个服务。
token
/hi
,不需要权限,只要 token
正确即可 /hello
,提示需要 ROLE_ADMIN
权限 role
表,添加 权限信息 ROLE_ADMIN
,然后在 user_role
表关联下再次访问 本案列架构有仍有改进之处。例如在 资源服务器 加一个 登录接口 ,该接口不受 Spring Security
保护。登录成功后, service-hi
远程调用 auth-service
获取 token
返回给浏览器,浏览器以后所有的请求都需要携带该 token
。
这个架构的缺陷就是, 每次请求 都需要由 资源服务 内部 远程调用 service-auth
服务来 验证 token
的正确性,以及该 token
对应的用户所具有的 权限 ,多了一次额外的 内部请求开销 。如果在 高并发 的情况下, service-auth
需要以 集群 的方式部署,并且需要做 缓存处理 。所以最佳方案还是结合 Spring Security OAuth2
和 JWT
一起使用,来实现 Spring Cloud
微服务系统的 认证 和 授权 。