用Spring Cloud OAuth2保護微服務系統

1、簡介#

OAth2是一個標準的受權協議。html

在認證與受權的過程當中,主要包含如下3種角色。java

  • 服務提供方 Authorization Server。
  • 資源持有者 Resource Server。
  • 客戶端 Client。

OAuth2的認證流程如圖所示,具體以下。mysql

(1)用戶(資源持有者)打開客戶端 ,客戶端詢問用戶受權。web

(2)用戶贊成受權。spring

(3)客戶端向受權服務器申請受權。sql

(4)受權服務器對客戶端進行認證,也包括用戶信息的認證,認證成功後受權給予令牌。數據庫

(5)客戶端獲取令牌後,攜帶令牌向資源服務器請求資源。apache

(6)資源服務器確認令牌正確無誤,向客戶端釋放資源。瀏覽器

OAuth2 Provider 的角色被分爲 Authorization Server(受權服務)和 Resource Service(資源服務),一般它們不在同一個服務中,可能一個 Authorization Service 對應多個 Resource Service。Spring OAuth2 需配合 Spring Security 一塊兒使用,全部的請求由 Spring MVC 控制器處理,並通過一系列的Spring Security過濾器。緩存

在Spring Security過濾器鏈中有如下兩個節點,這兩個節點是向 Authorization Service 獲取驗證和受權的。

  • 受權節點:默認爲 /oauth/authorize。
  • 獲取Token節點:默認爲 /oauth/token。

2、快速開始#

2.1 新建本地數據庫#

客戶端信息能夠存儲在數據庫中,這樣就能夠經過更改數據庫來實時更新客戶端信息的數據。Spring OAuth2 已經設計好了數據庫的表,且不可變。

Copy
/* Navicat MySQL Data Transfer Source Host : localhost Source Database : spring-cloud-auth Target Server Version : 50718 File Encoding : utf-8 */ 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;

2.2 新建Maven工程#

整個項目採用的是Maven多Module的形式,因此須要你新建一個空白的Maven工程,並在根目錄的pom.xml的配置Spring Boot的版本1.5.3.RELEASE,Spring Cloud的版本爲Dalston.RELEASE,參考代碼

Copy
<?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>cn.yueshutong</groupId> <artifactId>spring-cloud-autho2</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-cloud-autho2</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> 

2.3 編寫 Eureka Server#

新建模塊eureka-server,並添加Eureka依賴,此處要指定父工程

Copy
<?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>cn.yueshutong</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>cn.yueshutong</groupId> <artifactId>spring-cloud-autho2</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

Copy
server:  port: 8761 eureka:  instance:  hostname: localhost  client:  registerWithEureka: false  fetchRegistry: false  serviceUrl:  defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

最後,添加@EnableEurekaServer註解開啓Eureka Server的功能

Copy
@EnableEurekaServer @SpringBootApplication public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }

2.4 編寫 Uaa 受權服務#

1.新建模塊service-auth,並加入下列依賴,做爲Uaa(受權服務)

Copy
<?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>cn.yueshutong</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>cn.yueshutong</groupId> <artifactId>spring-cloud-autho2</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依賴能夠看到,它已經整合了spring-cloud-starter-security、spring-security-oauth2 和 spring-security-jwt 這3個起步依賴。

2.配置 application.yml 作以下配置

Copy
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 Boot1.5.x 版本以前,默認便可。

3.配置Spring Security

因爲 auth-service 須要對外暴露檢查 Token 的API接口,因此 auth-service 也是一個資源服務,須要在工程中引入 Spring Security,並作相關配置,對 auth-service 資源進行保護。

Copy
@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 @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }

UserServiceDetail.java

Copy
@Service public class UserServiceDetail implements UserDetailsService { @Autowired private UserDao userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userRepository.findByUsername(username); } }

User.java,須要實現 UserDetails 接口

Copy
@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; public User() { } @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.java,須要實現GrantedAuthority接口

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

UserDao.java

Copy
public interface UserDao extends JpaRepository<User, Long> { User findByUsername(String username); }

4.配置Authorization Server

Copy
@SpringBootApplication @EnableResourceServer //開啓資源服務,由於程序須要對外暴露獲取token的API接口 @EnableEurekaClient //開啓Eureka Client public class ServiceAuthApplication { @Autowired @Qualifier("dataSource") private DataSource dataSource; public static void main(String[] args) { SpringApplication.run(ServiceAuthApplication.class, args); } @Configuration @EnableAuthorizationServer //開啓受權服務的功能 protected class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter { //將Token存儲在內存中 //private TokenStore tokenStore = new InMemoryTokenStore(); JdbcTokenStore tokenStore=new JdbcTokenStore(dataSource); @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Autowired private UserServiceDetail userServiceDetail; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { //ClientDetailsServiceConfigurer配置了客戶端的一些基本信息 clients.inMemory() //將客戶端的信息存儲在內存中 .withClient("browser") //建立了一個client名爲browser的客戶端 .authorizedGrantTypes("refresh_token", "password")//配置驗證類型 .scopes("ui")//配置客戶端域爲「ui」 .and() .withClient("service-hi") .secret("123456") .authorizedGrantTypes("client_credentials", "refresh_token","password") .scopes("server"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore) //Token的存儲方式爲內存 .authenticationManager(authenticationManager) //WebSecurity配置好的 .userDetailsService(userServiceDetail);//讀取用戶的驗證信息 } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { //配置獲取Token的策略 oauthServer .tokenKeyAccess("permitAll()") //對獲取Token的請求再也不攔截 .checkTokenAccess("isAuthenticated()"); //驗證獲取Token的驗證信息 } } }

5.暴露Remote Token Service接口

本例採用 RemoteTokenService 這種方式對 Token 進行驗證。若是其餘資源服務須要驗證 Token,則須要遠程調用受權服務暴露的驗證 Token 的API接口。

Copy
@RestController @RequestMapping("/users") public class UserController { //暴露Remote Token Services接口 //若是其它服務須要驗證Token,則須要遠程調用受權服務暴露的驗證Token的API接口 @RequestMapping(value = "/current", method = RequestMethod.GET) public Principal getUser(Principal principal) { return principal; } }

2.6 編寫service-hi資源服務#

1.新建模塊 service-hi ,這個工程做爲資源服務。在pom文件引入以下依賴

Copy
<?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>cn.yueshutong</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>cn.yueshutong</groupId> <artifactId>spring-cloud-autho2</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> 

2.配置application.yml文件

Copy
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

3.配置 Resource Server

server-hi 工程做爲 Resource Server(資源服務),須要配置 Resource Server的相關配置,配置代碼

Copy
@Configuration @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true)//開啓方法級別的保護 public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { //配置哪些請求須要驗證 http.authorizeRequests() .antMatchers("/user/registry").permitAll() .anyRequest().authenticated(); } }

4.配置OAuth2 Client

Copy
@EnableOAuth2Client //開啓OAuth2Client @EnableConfigurationProperties @Configuration public class OAuth2ClientConfig { @Bean @ConfigurationProperties(prefix = "security.oauth2.client")//獲取Bean的配置屬性 public ClientCredentialsResourceDetails clientCredentialsResourceDetails() { //配置受保護資源的信息 return new ClientCredentialsResourceDetails(); } /** * @EnableOAuth2Client. * 1.oauth2ClientContextFilter * 2.AccessTokenRequest */ @Bean public RequestInterceptor oauth2FeignRequestInterceptor(){ //配置一個過濾器,存儲當前請求和上下文 //在request域內建立 AccessTokenRequest 類型的Bean。 return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), clientCredentialsResourceDetails()); } @Bean public OAuth2RestTemplate clientCredentialsRestTemplate() { //向Uaa服務請求的 return new OAuth2RestTemplate(clientCredentialsResourceDetails()); } }

5.編寫用戶註冊接口

把service-auth的User.java、UserDao.java拷貝到service-hi工程。

Service層的UserServiceImpl類建立用戶,其中須要對密碼進行加密

Copy
@Service public class UserService { private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); @Autowired private UserDao userDao; public User create(String username, String password) { User user=new User(); user.setUsername(username); String hash = encoder.encode(password); user.setPassword(hash); User u=userDao.save(user); return u; } }

編寫UserController.java

Copy
@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); } }

編寫HiController類

Copy
@RestController public class HiController { Logger logger= LoggerFactory.getLogger(HiController.class); @Value("${server.port}") String port; //不須要任何權限,只要Header中的Token正確便可 @RequestMapping("/hi") public String home() { return "hi :"+",i am from port:" +port; } //須要ROLE_ADMIN權限 @PreAuthorize("hasAuthority('ROLE_ADMIN')") // @RequestMapping("/hello") public String hello (){ return "hello you!"; } //獲取當前「Token」用戶信息 @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; } }

6.啓動類

Copy
@SpringBootApplication @EnableEurekaClient public class ServiceHiApplication { public static void main(String[] args) { SpringApplication.run(ServiceHiApplication.class, args); } } 

下面依次啓動這3個工程。

2.7 PostMan驗證#

1.註冊用戶,返回註冊成功信息

2.獲取Token

3.訪問/hi,不須要權限,只要Token正確便可

4.訪問/hello,須要ROLE_ADMIN權限

訪問不成功,在數據庫role表添加權限信息ROLE_ADMIN,而後在user_role表關聯下,再次訪問。

須要注意的是Token在Header的位置,以及前戳。

總結#

本案列架構有改進之處。例如在資源服務器加一個登陸接口,該接口不受Spring Security 保護。登陸成功後,service-hi 遠程調用 auth-service 獲取 Token 返回給瀏覽器,瀏覽器之後全部的請求都須要攜帶該 Token。 這個架構的缺陷就是每次請求都須要資源服務內部遠程調用 auth-service 服務來驗證 Token 的正確性,以及該Token對應的用戶所具備的權限,額外多了一次內部請求。若是在高併發的狀況下,auth-service 須要集羣部署,而且須要作緩存處理。因此最佳方案仍是使用 Spring Security OAuth2 以JWT的形式來保護Spring Cloud構建的微服務系統。

相關文章
相關標籤/搜索