javascript
SpringSecurity OAuth2.0认证授权-part2
此篇文章包含oauth2項(xiàng)目搭建、整合jwt、授權(quán)方式測試;
篇幅過長,拆分為:
part1: 認(rèn)證授權(quán)原理回顧及分布式系統(tǒng)認(rèn)證方案;
part2: oauth2項(xiàng)目搭建、授權(quán)方式測試;
part3: 整合jwt、網(wǎng)關(guān)、注冊中心 完善整套OAuth2.0
------------------------------------------------------------------------------------
3. OAuth2.0
3.1 OAuth2.0介紹
OAuth(開放授權(quán))是一個開放標(biāo)準(zhǔn),允許用戶授權(quán)第三方應(yīng)用訪問他們存儲在另外的服務(wù)提供者上的信息,而不 需要將用戶名和密碼提供給第三方應(yīng)用或分享他們數(shù)據(jù)的所有內(nèi)容。OAuth2.0是OAuth協(xié)議的延續(xù)版本,但不向 后兼容OAuth 1.0即完全廢止了OAuth1.0。很多大公司如Google,Yahoo,Microsoft等都提供了OAUTH認(rèn)證服 務(wù),這些都足以說明OAUTH標(biāo)準(zhǔn)逐漸成為開放資源授權(quán)的標(biāo)準(zhǔn)。
Oauth協(xié)議目前發(fā)展到2.0版本,1.0版本過于復(fù)雜,2.0版本已得到廣泛應(yīng)用。
參考:oAuth_百度百科
Oauth協(xié)議:RFC 6749 - The OAuth 2.0 Authorization Framework?
下邊分析一個Oauth2認(rèn)證的例子,通過例子去理解OAuth2.0協(xié)議的認(rèn)證流程,本例子是某奇藝網(wǎng)站使用微信 認(rèn)證的過程,這個過程的簡要描述如下:
用戶借助微信認(rèn)證登錄某奇藝網(wǎng)站,用戶就不用單獨(dú)在某奇藝注冊用戶,怎么樣算認(rèn)證成功嗎?某奇藝網(wǎng)站需要成功從微信獲取用戶的身份信息則認(rèn)為用戶認(rèn)證成功,那如何從微信獲取用戶的身份信息?用戶信息的 擁有者是用戶本人,微信需要經(jīng)過用戶的同意方可為某奇藝網(wǎng)站生成令牌,某奇藝網(wǎng)站拿此令牌方可從微 信獲取用戶的信息。
1、客戶端請求第三方授權(quán) 用戶進(jìn)入黑馬程序的登錄頁面,點(diǎn)擊微信的圖標(biāo)以微信賬號登錄系統(tǒng),用戶是自己在微信里信息的資源擁有者。
?點(diǎn)擊“微信”出現(xiàn)一個二維碼,此時用戶掃描二維碼,開始給某奇異授權(quán)
?2、資源擁有者同意給客戶端授權(quán) 資源擁有者掃描二維碼表示資源擁有者同意給客戶端授權(quán),微信會對資源擁有者的身份進(jìn)行驗(yàn)證, 驗(yàn)證通過后,微 信會詢問用戶是否給授權(quán)某奇異訪問自己的微信數(shù)據(jù),用戶點(diǎn)擊“確認(rèn)登錄”表示同意授權(quán),微信認(rèn)證服務(wù)器會 頒發(fā)一個授權(quán)碼,并重定向到某奇異的網(wǎng)站。
3、客戶端獲取到授權(quán)碼,請求認(rèn)證服務(wù)器申請令牌 此過程用戶看不到,客戶端應(yīng)用程序請求認(rèn)證服務(wù)器,請求攜帶授權(quán)碼。
4、認(rèn)證服務(wù)器向客戶端響應(yīng)令牌 微信認(rèn)證服務(wù)器驗(yàn)證了客戶端請求的授權(quán)碼,如果合法則給客戶端頒發(fā)令牌,令牌是客戶端訪問資源的通行證。 此交互過程用戶看不到,當(dāng)客戶端拿到令牌后,用戶在黑馬程序員看到已經(jīng)登錄成功。
5、客戶端請求資源服務(wù)器的資源 客戶端攜帶令牌訪問資源服務(wù)器的資源。 黑馬程序員網(wǎng)站攜帶令牌請求訪問微信服務(wù)器獲取用戶的基本信息。
6、資源服務(wù)器返回受保護(hù)資源 資源服務(wù)器校驗(yàn)令牌的合法性,如果合法則向用戶響應(yīng)資源信息內(nèi)容。
以上認(rèn)證授權(quán)詳細(xì)的執(zhí)行流程如下:
通過上邊的例子我們大概了解了OAauth2.0的認(rèn)證過程,下邊我們看OAuth2.0認(rèn)證流程:
引自O(shè)Aauth2.0協(xié)議rfc6749 RFC 6749 - The OAuth 2.0 Authorization Framework?
OAauth2.0包括以下角色:
1、客戶端
本身不存儲資源,需要通過資源擁有者的授權(quán)去請求資源服務(wù)器的資源,比如:Android客戶端、Web客戶端(瀏 覽器端)、微信客戶端等。
2、資源擁有者
通常為用戶,也可以是應(yīng)用程序,即該資源的擁有者。
3、授權(quán)服務(wù)器(也稱認(rèn)證服務(wù)器)
用于服務(wù)提供商對資源擁有的身份進(jìn)行認(rèn)證、對訪問資源進(jìn)行授權(quán),認(rèn)證成功后會給客戶端發(fā)放令牌 (access_token),作為客戶端訪問資源服務(wù)器的憑據(jù)。本例為微信的認(rèn)證服務(wù)器。
4、資源服務(wù)器
存儲資源的服務(wù)器,本例子為微信存儲的用戶信息。
現(xiàn)在還有一個問題,服務(wù)提供商能允許隨便一個客戶端就接入到它的授權(quán)服務(wù)器嗎?答案是否定的,服務(wù)提供商會 給準(zhǔn)入的接入方一個身份,用于接入時的憑據(jù):
client_id:客戶端標(biāo)識 client_secret:客戶端秘鑰
因此,準(zhǔn)確來說,授權(quán)服務(wù)器對兩種OAuth2.0中的兩個角色進(jìn)行認(rèn)證授權(quán),分別是資源擁有者、客戶端。
3.2 Spring Cloud Security OAuth2
3.2.1 環(huán)境介紹
Spring-Security-OAuth2是對OAuth2的一種實(shí)現(xiàn),并且跟我們之前學(xué)習(xí)的Spring Security相輔相成,與Spring Cloud體系的集成也非常便利,接下來,我們需要對它進(jìn)行學(xué)習(xí),最終使用它來實(shí)現(xiàn)我們設(shè)計(jì)的分布式認(rèn)證授權(quán)解 決方案。
OAuth2.0的服務(wù)提供方涵蓋兩個服務(wù),即授權(quán)服務(wù) (Authorization Server,也叫認(rèn)證服務(wù)) 和資源服務(wù) (Resource Server),使用 Spring Security OAuth2 的時候你可以選擇把它們在同一個應(yīng)用程序中實(shí)現(xiàn),也可以選擇建立使用 同一個授權(quán)服務(wù)的多個資源服務(wù)。
授權(quán)服務(wù) (Authorization Server)應(yīng)包含對接入端以及登入用戶的合法性進(jìn)行驗(yàn)證并頒發(fā)token等功能,對令牌 的請求端點(diǎn)由 Spring MVC 控制器進(jìn)行實(shí)現(xiàn),下面是配置一個認(rèn)證服務(wù)必須要實(shí)現(xiàn)的endpoints:
-
AuthorizationEndpoint 服務(wù)于認(rèn)證請求。默認(rèn) URL: /oauth/authorize 。
-
TokenEndpoint 服務(wù)于訪問令牌的請求。默認(rèn) URL: /oauth/token 。 資源服務(wù) (Resource Server),應(yīng)包含對資源的保護(hù)功能,對非法請求進(jìn)行攔截,對請求中token進(jìn)行解析鑒 權(quán)等,下面的過濾器用于實(shí)現(xiàn) OAuth 2.0 資源服務(wù):
-
OAuth2AuthenticationProcessingFilter用來對請求給出的身份令牌解析鑒權(quán)。
認(rèn)證流程如下:
1、客戶端請求oauth授權(quán)服務(wù)進(jìn)行認(rèn)證。
2、認(rèn)證通過后由oauth頒發(fā)令牌。
3、客戶端攜帶令牌Token請求資源服務(wù)。
4、資源服務(wù)校驗(yàn)令牌的合法性,合法即返回資源信息。
3.2.2 環(huán)境搭建
3.2.2.1 父工程
創(chuàng)建maven工程作為父工程,依賴如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion> ?<groupId>com.panghl</groupId><artifactId>oauth2-parent</artifactId><version>1.0-SNAPSHOT</version><modules><module>security-eureka</module><module>security-gateway</module><module>security-order</module><module>security-auth</module></modules><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.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>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version></dependency> ? ?<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-jwt</artifactId><version>1.0.9.RELEASE</version></dependency> ? ?<dependency><groupId>org.springframework.security.oauth.boot</groupId><artifactId>spring-security-oauth2-autoconfigure</artifactId><version>2.1.2.RELEASE</version></dependency> ? ?</dependencies></dependencyManagement> ? ?<build><finalName>${project.name}</finalName><resources><resource><directory>src/main/resources</directory><filtering>true</filtering><includes><include>**/*</include></includes></resource><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource></resources><plugins><!--<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin>--> ?<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.2.2.2 創(chuàng)建oauth授權(quán)服務(wù)工程
1、創(chuàng)建security-auth
創(chuàng)建security-auth作為授權(quán)服務(wù)工程,依賴如下:
<?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>oauth2-parent</artifactId><groupId>com.panghl</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion> ?<groupId>com.panghl</groupId><artifactId>security-auth</artifactId><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency> ?<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency> ?<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency> ?<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency> ?<dependency><groupId>com.netflix.hystrix</groupId><artifactId>hystrix-javanica</artifactId></dependency> ?<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId></dependency> ?<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency> ?<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> ?<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</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>javax.interceptor</groupId><artifactId>javax.interceptor-api</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>com.alibaba</groupId><artifactId>fastjson</artifactId></dependency> ?<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies> ? </project>工程結(jié)構(gòu)如下:
2、啟動類
/*** @Author panghl* @Date 2022/2/20* 授權(quán)服務(wù)**/ @SpringBootApplication @EnableDiscoveryClient @EnableHystrix @EnableFeignClients(basePackages = {"com.panghl.auth"}) public class OauthServer { ?public static void main(String[] args) {SpringApplication.run(OauthServer.class,args);} }3、配置文件
在resources下創(chuàng)建application.yml
server:port: 8005 spring:application:name: security-auth ?datasource:url: jdbc:mysql://192.168.31.66:3306/oauth2?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8username: rootpassword: passwordmain:allow-bean-definition-overriding: true eureka:instance:prefer-ip-address: trueclient:service-url:defaultZone: http://127.0.0.1:8001/eureka ? feign:hystrix:enabled: true3.2.2.3 創(chuàng)建Order資源服務(wù)工程
本工程為Order訂單服務(wù)工程,訪問本工程的資源需要認(rèn)證通過。
本工程的目的主要是測試認(rèn)證授權(quán)的功能,所以不涉及訂單管理相關(guān)業(yè)務(wù)。
1、創(chuàng)建Order工程
<?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>oauth2-parent</artifactId><groupId>com.panghl</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion> ?<groupId>com.panghl</groupId><artifactId>security-order</artifactId><dependencies> ?<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency> ?<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</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-security</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency><groupId>javax.interceptor</groupId><artifactId>javax.interceptor-api</artifactId></dependency> ?<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId></dependency> ?<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency> ? ?</dependencies> ? </project>2、工程結(jié)構(gòu)
3、配置文件
server:port: 8004 spring:application:name: security-order ?datasource:url: jdbc:mysql://192.168.31.66:3306/oauth2?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8username: rootpassword: passwordmain:allow-bean-definition-overriding: true eureka:instance:prefer-ip-address: trueclient:service-url:defaultZone: http://127.0.0.1:8001/eurekaDB環(huán)境準(zhǔn)備
CREATE DATABASE `oauth2`CREATE TABLE `oauth_client_details` (`client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客戶端標(biāo)\r\n識',`resource_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '接入資源列表',`client_secret` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '客戶端秘鑰',`scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,`authorized_grant_types` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,`web_server_redirect_uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,`authorities` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,`access_token_validity` int DEFAULT NULL,`refresh_token_validity` int DEFAULT NULL,`additional_information` longtext CHARACTER SET utf8 COLLATE utf8_general_ci,`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`archived` tinyint DEFAULT NULL,`trusted` tinyint DEFAULT NULL,`autoapprove` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,PRIMARY KEY (`client_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='接入客戶端信息';INSERT INTO oauth2.oauth_client_details (client_id, resource_ids, client_secret, `scope`, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, create_time, archived, trusted, autoapprove) VALUES('c1', 'res1', '$2a$10$ef4BQKzyliCf9db9DUKYme83iPbCBP9ZMXpBamK1E94kWquv3Qx7q', 'ROLE_ADMIN,ROLE_USER,ROLE_API', 'client_credentials,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com', NULL, 7200, 259200, NULL, '2022-02-20 08:15:12', 0, 0, 'false'); INSERT INTO oauth2.oauth_client_details (client_id, resource_ids, client_secret, `scope`, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, create_time, archived, trusted, autoapprove) VALUES('c2', 'res2', '$2a$10$ef4BQKzyliCf9db9DUKYme83iPbCBP9ZMXpBamK1E94kWquv3Qx7q', 'ROLE_API', 'client_credentials,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com', NULL, 31536000, 2592000, NULL, '2022-02-20 08:15:13', 0, 0, 'false');-- oauth2.oauth_code definitionCREATE TABLE `oauth_code` (`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,`code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,`authentication` blob,KEY `code_index` (`code`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=COMPACT;CREATE TABLE `t_user` (`id` bigint NOT NULL COMMENT '用戶id',`username` varchar(64) NOT NULL,`password` varchar(64) NOT NULL,`fullname` varchar(255) NOT NULL COMMENT '用戶姓名',`mobile` varchar(11) DEFAULT NULL COMMENT '手機(jī)號',PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC; INSERT INTO oauth2.t_user (id, username, password, fullname, mobile) VALUES(1, '張三', '$2a$10$cRGf/jYto/ciEB14IyJxreq1ZG7GVjN.Bm9NcktzFx4gJ8/LOsyAq', '111', '11');-- oauth2.t_role definitionCREATE TABLE `t_role` (`id` varchar(32) NOT NULL,`role_name` varchar(255) DEFAULT NULL,`description` varchar(255) DEFAULT NULL,`create_time` datetime DEFAULT NULL,`update_time` datetime DEFAULT NULL,`status` char(1) NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `unique_role_name` (`role_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; INSERT INTO oauth2.t_role (id, role_name, description, create_time, update_time, status) VALUES('1', '管理員', NULL, NULL, NULL, ''); -- oauth2.t_user_role definitionCREATE TABLE `t_user_role` (`user_id` varchar(32) NOT NULL,`role_id` varchar(32) NOT NULL,`create_time` datetime DEFAULT NULL,`creator` varchar(255) DEFAULT NULL,PRIMARY KEY (`user_id`,`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; INSERT INTO oauth2.t_user_role (user_id, role_id, create_time, creator) VALUES('1', '1', NULL, NULL); -- oauth2.t_permission definitionCREATE TABLE `t_permission` (`id` varchar(32) NOT NULL,`code` varchar(32) NOT NULL COMMENT '權(quán)限標(biāo)識符',`description` varchar(64) DEFAULT NULL COMMENT '描述',`url` varchar(128) DEFAULT NULL COMMENT '請求地址',PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; INSERT INTO oauth2.t_permission (id, code, description, url) VALUES('1', 'p1', '測試資源 1', '/r/r1'); INSERT INTO oauth2.t_permission (id, code, description, url) VALUES('2', 'p3', '測試資源2', '/r/r2'); -- oauth2.t_role_permission definitionCREATE TABLE `t_role_permission` (`role_id` varchar(32) NOT NULL,`permission_id` varchar(32) NOT NULL,PRIMARY KEY (`role_id`,`permission_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;INSERT INTO oauth2.t_role_permission (role_id, permission_id) VALUES('1', '1'); INSERT INTO oauth2.t_role_permission (role_id, permission_id) VALUES('1', '2');3.2.2.授權(quán)服務(wù)器配置
3.2.2.1 EnableAuthorizationServer
可以用 @EnableAuthorizationServer 注解并繼承AuthorizationServerConfigurerAdapter來配置OAuth2.0 授權(quán) 服務(wù)器。
在Config包下創(chuàng)建AuthorizationServer: [配置信息后面會說明]
@Configuration @EnableAuthorizationServer public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {@Autowiredprivate TokenStore tokenStore;//客戶端詳情服務(wù)@Autowiredprivate ClientDetailsService clientDetailsService;@Autowiredprivate AuthorizationCodeServices authorizationCodeServices;@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate PasswordEncoder passwordEncoder;// 令牌管理服務(wù)@Beanpublic AuthorizationServerTokenServices tokenService() {DefaultTokenServices service=new DefaultTokenServices();service.setClientDetailsService(clientDetailsService); // 客戶端信息服務(wù)service.setSupportRefreshToken(true);// 是否產(chǎn)生刷新令牌service.setTokenStore(tokenStore);//令牌存儲策略// 令牌增強(qiáng)//TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();//tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));//service.setTokenEnhancer(tokenEnhancerChain);service.setAccessTokenValiditySeconds(7200); // 令牌默認(rèn)有效期2小時service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默認(rèn)有效期3天return service;}@Beanpublic AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {//設(shè)置授權(quán)碼模式的授權(quán)碼如何存取,暫時采用內(nèi)存方式return new InMemoryAuthorizationCodeServices();}/*** 用來配置客戶端詳情服務(wù)(ClientDetailsService),客戶端詳情信息在* 這里進(jìn)行初始化,你能夠把客戶端詳情信息寫死在這里或者是通過數(shù)據(jù)庫來存儲調(diào)取詳情信息。* @param clients* @throws Exception*/@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {// clients.withClientDetails(clientDetailsService);// 暫時使用內(nèi)存方式clients.inMemory()// 使用in‐memory存儲.withClient("c1")// client_id.secret(new BCryptPasswordEncoder().encode("secret")) //客戶端密鑰.resourceIds("res1") //資源列表.authorizedGrantTypes("authorization_code","password","client_credentials","implicit","refresh_token")// 該client允許的授權(quán)類型 uthorization_code,password,refresh_token,implicit,client_credentials.scopes("all")// 允許的授權(quán)范圍.autoApprove(false)// false 跳轉(zhuǎn)到授權(quán)頁面//加上驗(yàn)證回調(diào)地址.redirectUris("http://www.baidu.com");}/*** 用來配置令牌(token)的訪問端點(diǎn)和令牌服務(wù)(token services)。* /oauth/authorize:授權(quán)端點(diǎn)。* /oauth/token:令牌端點(diǎn)。* /oauth/confirm_access:用戶確認(rèn)授權(quán)提交端點(diǎn)。* /oauth/error:授權(quán)服務(wù)錯誤信息端點(diǎn)。* /oauth/check_token:用于資源服務(wù)訪問的令牌解析端點(diǎn)。* /oauth/token_key:提供公有密匙的端點(diǎn),如果你使用JWT令牌的話。* @param endpoints* @throws Exception*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager) //密碼模式需要.authorizationCodeServices(authorizationCodeServices) //授權(quán)碼模式需要.tokenServices(tokenService()) // 令牌管理服務(wù).allowedTokenEndpointRequestMethods(HttpMethod.POST); //允許POST提交}/*** 用來配置令牌端點(diǎn)的安全約束* @param security* @throws Exception*/@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.tokenKeyAccess("permitAll()") //tokenkey這個endpoint當(dāng)使用JwtToken且使用非對稱加密時,資源服務(wù)用于獲取公鑰而開放的,這里指這個 endpoint完全公開。.checkTokenAccess("permitAll()") //checkToken這個endpoint完全公開.allowFormAuthenticationForClients(); // 允許表單認(rèn)證}}AuthorizationServerConfigurerAdapter要求配置以下幾個類,這幾個類是由Spring創(chuàng)建的獨(dú)立的配置對象,它們 會被Spring傳入AuthorizationServerConfigurer中進(jìn)行配置。
ClientDetailsServiceConfigurer:用來配置客戶端詳情服務(wù)(ClientDetailsService),客戶端詳情信息在 這里進(jìn)行初始化,你能夠把客戶端詳情信息寫死在這里或者是通過數(shù)據(jù)庫來存儲調(diào)取詳情信息。
AuthorizationServerEndpointsConfigurer:用來配置令牌(token)的訪問端點(diǎn)和令牌服務(wù)(token services)。
AuthorizationServerSecurityConfigurer:用來配置令牌端點(diǎn)的安全約束.
3.2.2.2.配置客戶端詳細(xì)信息
ClientDetailsServiceConfigurer 能夠使用內(nèi)存或者JDBC來實(shí)現(xiàn)客戶端詳情服務(wù)(ClientDetailsService), ClientDetailsService負(fù)責(zé)查找ClientDetails,而ClientDetails有幾個重要的屬性如下列表:
-
clientId:(必須的)用來標(biāo)識客戶的Id。
-
secret:(需要值得信任的客戶端)客戶端安全碼,如果有的話。
-
scope:用來限制客戶端的訪問范圍,如果為空(默認(rèn))的話,那么客戶端擁有全部的訪問范圍。
-
authorizedGrantTypes:此客戶端可以使用的授權(quán)類型,默認(rèn)為空。
-
authorities:此客戶端可以使用的權(quán)限(基于Spring Security authorities)。
客戶端詳情(Client Details)能夠在應(yīng)用程序運(yùn)行的時候進(jìn)行更新,可以通過訪問底層的存儲服務(wù)(例如將客戶 端詳情存儲在一個關(guān)系數(shù)據(jù)庫的表中,就可以使用 JdbcClientDetailsService)或者通過自己實(shí)現(xiàn) ClientRegistrationService接口(同時你也可以實(shí)現(xiàn) ClientDetailsService 接口)來進(jìn)行管理。
/*** 用來配置客戶端詳情服務(wù)(ClientDetailsService),客戶端詳情信息在* 這里進(jìn)行初始化,你能夠把客戶端詳情信息寫死在這里或者是通過數(shù)據(jù)庫來存儲調(diào)取詳情信息。* @param clients* @throws Exception*/ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.withClientDetails(clientDetailsService);// 暫時使用內(nèi)存方式clients.inMemory()// 使用in‐memory存儲.withClient("c1")// client_id.secret(new BCryptPasswordEncoder().encode("secret")) //客戶端密鑰.resourceIds("res1") //資源列表.authorizedGrantTypes("authorization_code","password","client_credentials","implicit","refresh_token")// 該client允許的授權(quán)類型 uthorization_code,password,refresh_token,implicit,client_credentials.scopes("all")// 允許的授權(quán)范圍.autoApprove(false)// false 跳轉(zhuǎn)到授權(quán)頁面//加上驗(yàn)證回調(diào)地址.redirectUris("http://www.baidu.com"); }3.2.2.4.管理令牌
AuthorizationServerTokenServices 接口定義了一些操作使得你可以對令牌進(jìn)行一些必要的管理,令牌可以被用來 加載身份信息,里面包含了這個令牌的相關(guān)權(quán)限。
自己可以創(chuàng)建 AuthorizationServerTokenServices 這個接口的實(shí)現(xiàn),則需要繼承 DefaultTokenServices 這個類, 里面包含了一些有用實(shí)現(xiàn),你可以使用它來修改令牌的格式和令牌的存儲。默認(rèn)的,當(dāng)它嘗試創(chuàng)建一個令牌的時 候,是使用隨機(jī)值來進(jìn)行填充的,除了持久化令牌是委托一個 TokenStore 接口來實(shí)現(xiàn)以外,這個類幾乎幫你做了 所有的事情。并且 TokenStore 這個接口有一個默認(rèn)的實(shí)現(xiàn),它就是 InMemoryTokenStore ,如其命名,所有的 令牌是被保存在了內(nèi)存中。除了使用這個類以外,你還可以使用一些其他的預(yù)定義實(shí)現(xiàn),下面有幾個版本,它們都 實(shí)現(xiàn)了TokenStore接口:
-
InMemoryTokenStore:這個版本的實(shí)現(xiàn)是被默認(rèn)采用的,它可以完美的工作在單服務(wù)器上(即訪問并發(fā)量 壓力不大的情況下,并且它在失敗的時候不會進(jìn)行備份),大多數(shù)的項(xiàng)目都可以使用這個版本的實(shí)現(xiàn)來進(jìn)行 嘗試,你可以在開發(fā)的時候使用它來進(jìn)行管理,因?yàn)椴粫槐4娴酱疟P中,所以更易于調(diào)試。
-
JdbcTokenStore:這是一個基于JDBC的實(shí)現(xiàn)版本,令牌會被保存進(jìn)關(guān)系型數(shù)據(jù)庫。使用這個版本的實(shí)現(xiàn)時, 你可以在不同的服務(wù)器之間共享令牌信息,使用這個版本的時候請注意把"spring-jdbc"這個依賴加入到你的 classpath當(dāng)中。
-
JwtTokenStore:這個版本的全稱是 JSON Web Token(JWT),它可以把令牌相關(guān)的數(shù)據(jù)進(jìn)行編碼(因此對 于后端服務(wù)來說,它不需要進(jìn)行存儲,這將是一個重大優(yōu)勢),但是它有一個缺點(diǎn),那就是撤銷一個已經(jīng)授 權(quán)令牌將會非常困難,所以它通常用來處理一個生命周期較短的令牌以及撤銷刷新令牌(refresh_token)。 另外一個缺點(diǎn)就是這個令牌占用的空間會比較大,如果你加入了比較多用戶憑證信息。JwtTokenStore 不會保存任何數(shù)據(jù),但是它在轉(zhuǎn)換令牌值以及授權(quán)信息方面與 DefaultTokenServices 所扮演的角色是一樣的。
1、定義TokenConfig
在config包下定義TokenConfig,我們暫時先使用InMemoryTokenStore,生成一個普通的令牌。
@Configuration public class TokenConfig {// 令牌存儲策略@Beanpublic TokenStore tokenStore() {// 內(nèi)存方式,生成普通令牌return new InMemoryTokenStore();} }2、定義AuthorizationServerTokenServices
在AuthorizationServer中定義AuthorizationServerTokenServices
@Autowiredprivate TokenStore tokenStore;//客戶端詳情服務(wù)@Autowiredprivate ClientDetailsService clientDetailsService;// 令牌管理服務(wù)@Beanpublic AuthorizationServerTokenServices tokenService() {DefaultTokenServices service=new DefaultTokenServices();service.setClientDetailsService(clientDetailsService); // 客戶端信息服務(wù)service.setSupportRefreshToken(true);// 是否產(chǎn)生刷新令牌service.setTokenStore(tokenStore);//令牌存儲策略service.setAccessTokenValiditySeconds(7200); // 令牌默認(rèn)有效期2小時service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默認(rèn)有效期3天return service;}3.2.2.5.令牌訪問端點(diǎn)配置
AuthorizationServerEndpointsConfigurer 這個對象的實(shí)例可以完成令牌服務(wù)以及令牌endpoint配置。
配置授權(quán)類型(Grant Types)
-
AuthorizationServerEndpointsConfigurer 通過設(shè)定以下屬性決定支持的授權(quán)類型(Grant Types):
-
authenticationManager:認(rèn)證管理器,當(dāng)你選擇了資源所有者密碼(password)授權(quán)類型的時候,請?jiān)O(shè)置 這個屬性注入一個 AuthenticationManager 對象。
-
userDetailsService:如果你設(shè)置了這個屬性的話,那說明你有一個自己的 UserDetailsService 接口的實(shí)現(xiàn), 或者你可以把這個東西設(shè)置到全局域上面去(例如 GlobalAuthenticationManagerConfigurer 這個配置對 象),當(dāng)你設(shè)置了這個之后,那么 "refresh_token" 即刷新令牌授權(quán)類型模式的流程中就會包含一個檢查,用 來確保這個賬號是否仍然有效,假如說你禁用了這個賬戶的話。
-
authorizationCodeServices:這個屬性是用來設(shè)置授權(quán)碼服務(wù)的(即 AuthorizationCodeServices 的實(shí)例對 象),主要用于 "authorization_code" 授權(quán)碼類型模式。
-
implicitGrantService:這個屬性用于設(shè)置隱式授權(quán)模式,用來管理隱式授權(quán)模式的狀態(tài)。
-
tokenGranter:當(dāng)你設(shè)置了這個東西(即 TokenGranter 接口實(shí)現(xiàn)),那么授權(quán)將會交由你來完全掌控,并 且會忽略掉上面的這幾個屬性,這個屬性一般是用作拓展用途的,即標(biāo)準(zhǔn)的四種授權(quán)模式已經(jīng)滿足不了你的 需求的時候,才會考慮使用這個。
配置授權(quán)端點(diǎn)的URL(Endpoint URLs):
AuthorizationServerEndpointsConfigurer 這個配置對象有一個叫做 pathMapping() 的方法用來配置端點(diǎn)URL鏈 接,它有兩個參數(shù):
第一個參數(shù):String 類型的,這個端點(diǎn)URL的默認(rèn)鏈接。
第二個參數(shù):String 類型的,你要進(jìn)行替代的URL鏈接。
以上的參數(shù)都將以 "/" 字符為開始的字符串,框架的默認(rèn)URL鏈接如下列表,可以作為這個 pathMapping() 方法的 第一個參數(shù):
-
/oauth/authorize:授權(quán)端點(diǎn)。
-
/oauth/token:令牌端點(diǎn)。
-
/oauth/confirm_access:用戶確認(rèn)授權(quán)提交端點(diǎn)。
-
/oauth/error:授權(quán)服務(wù)錯誤信息端點(diǎn)。
-
/oauth/check_token:用于資源服務(wù)訪問的令牌解析端點(diǎn)。
-
/oauth/token_key:提供公有密匙的端點(diǎn),如果你使用JWT令牌的話。
需要注意的是授權(quán)端點(diǎn)這個URL應(yīng)該被Spring Security保護(hù)起來只供授權(quán)用戶訪問.
在AuthorizationServer配置令牌訪問端點(diǎn)
@Autowired private AuthorizationCodeServices authorizationCodeServices;@Autowired private AuthenticationManager authenticationManager;@Beanpublic AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {//設(shè)置授權(quán)碼模式的授權(quán)碼如何存取,暫時采用內(nèi)存方式//return new InMemoryAuthorizationCodeServices();return new JdbcAuthorizationCodeServices(dataSource);}/*** 用來配置令牌(token)的訪問端點(diǎn)和令牌服務(wù)(token services)。* /oauth/authorize:授權(quán)端點(diǎn)。* /oauth/token:令牌端點(diǎn)。* /oauth/confirm_access:用戶確認(rèn)授權(quán)提交端點(diǎn)。* /oauth/error:授權(quán)服務(wù)錯誤信息端點(diǎn)。* /oauth/check_token:用于資源服務(wù)訪問的令牌解析端點(diǎn)。* /oauth/token_key:提供公有密匙的端點(diǎn),如果你使用JWT令牌的話。* @param endpoints* @throws Exception*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager) //密碼模式需要.authorizationCodeServices(authorizationCodeServices) //授權(quán)碼模式需要.tokenServices(tokenService()) // 令牌管理服務(wù).allowedTokenEndpointRequestMethods(HttpMethod.POST); //允許POST提交}3.2.2.6.令牌端點(diǎn)的安全約束
AuthorizationServerSecurityConfigurer:用來配置令牌端點(diǎn)(Token Endpoint)的安全約束,在 AuthorizationServer中配置如下.
/*** 用來配置令牌端點(diǎn)的安全約束* @param security* @throws Exception*/ @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.tokenKeyAccess("permitAll()") //tokenkey這個endpoint當(dāng)使用JwtToken且使用非對稱加密時,資源服務(wù)用于獲取公鑰而開放的,這里指這個 endpoint完全公開。.checkTokenAccess("permitAll()") //checkToken這個endpoint完全公開.allowFormAuthenticationForClients(); // 允許表單認(rèn)證 }(1)tokenkey這個endpoint當(dāng)使用JwtToken且使用非對稱加密時,資源服務(wù)用于獲取公鑰而開放的,這里指這個 endpoint完全公開。
(2)checkToken這個endpoint完全公開
(3) 允許表單認(rèn)證
授權(quán)服務(wù)配置總結(jié):授權(quán)服務(wù)配置分成三大塊,可以關(guān)聯(lián)記憶。
既然要完成認(rèn)證,它首先得知道客戶端信息從哪兒讀取,因此要進(jìn)行客戶端詳情配置。
既然要頒發(fā)token,那必須得定義token的相關(guān)endpoint,以及token如何存取,以及客戶端支持哪些類型的 token。
既然暴露除了一些endpoint,那對這些endpoint可以定義一些安全上的約束等。
3.2.2.7 web安全配置
/*** @author Administrator* @version 1.0**/ @Configuration @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter {//認(rèn)證管理器@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}//密碼編碼器@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//安全攔截機(jī)制(最重要)@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/r/r1").hasAnyAuthority("p1").antMatchers("/login*").permitAll().anyRequest().authenticated().and().formLogin();}}3.2.3 授權(quán)碼模式
授權(quán)碼模式交互圖:
(1)資源擁有者打開客戶端,客戶端要求資源擁有者給予授權(quán),它將瀏覽器被重定向到授權(quán)服務(wù)器,重定向時會 附加客戶端的身份信息。如:
http://localhost:8005/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com
參數(shù)列表如下:
client_id:客戶端準(zhǔn)入標(biāo)識。
response_type:授權(quán)碼模式固定為code。
scope:客戶端權(quán)限。
redirect_uri:跳轉(zhuǎn)uri,當(dāng)授權(quán)碼申請成功后會跳轉(zhuǎn)到此地址,并在后邊帶上code參數(shù)(授權(quán)碼)。
(2)瀏覽器出現(xiàn)向授權(quán)服務(wù)器授權(quán)頁面,之后將用戶同意授權(quán)。
百度一下,你就知道
(3)授權(quán)服務(wù)器將授權(quán)碼(AuthorizationCode)轉(zhuǎn)經(jīng)瀏覽器發(fā)送給client(通過redirect_uri)。
(4)客戶端拿著授權(quán)碼向授權(quán)服務(wù)器索要訪問access_token,請求如下:
localhost:8005/oauth/token?code=MQzXkX&client_id=c1&client_secret=secret&username=zhangsan&password=123&grant_type=authorization_code&redirect_uri=http://www.baidu.com
參數(shù)列表如下
-
client_id:客戶端準(zhǔn)入標(biāo)識。
-
client_secret:客戶端秘鑰。
-
grant_type:授權(quán)類型,填寫authorization_code,表示授權(quán)碼模式
-
code:授權(quán)碼,就是剛剛獲取的授權(quán)碼,注意:授權(quán)碼只使用一次就無效了,需要重新申請。
-
redirect_uri:申請授權(quán)碼時的跳轉(zhuǎn)url,一定和申請授權(quán)碼時用的redirect_uri一致。
(5)授權(quán)服務(wù)器返回令牌(access_token)
這種模式是四種模式中最安全的一種模式。一般用于client是Web服務(wù)器端應(yīng)用或第三方的原生App調(diào)用資源服務(wù) 的時候。因?yàn)樵谶@種模式中access_token不會經(jīng)過瀏覽器或移動端的App,而是直接從服務(wù)端去交換,這樣就最大 限度的減小了令牌泄漏的風(fēng)險(xiǎn)。
3.2.3.2 測試
?
??
3.2.4 簡化模式
3.2.4.1 簡化模式介紹
簡化模式交互圖:
(1)資源擁有者打開客戶端,客戶端要求資源擁有者給予授權(quán),它將瀏覽器被重定向到授權(quán)服務(wù)器,重定向時會 附加客戶端的身份信息。如:
http://localhost:8005//oauth/authorize?client_id=c1&response_type=token&scope=all&redirect_uri=http://www.baidu.com參數(shù)描述同授權(quán)碼模式 ,注意response_type=token,說明是簡化模式。
(2)瀏覽器出現(xiàn)向授權(quán)服務(wù)器授權(quán)頁面,之后將用戶同意授權(quán)。
3)授權(quán)服務(wù)器將授權(quán)碼將令牌(access_token)以Hash的形式存放在重定向uri的fargment中發(fā)送給瀏覽 器。
https://www.baidu.com/#access_token=6257f954-3006-4e0d-a362-1b0ec67a3ac9&token_type=bearer&expires_in=7033注:fragment 主要是用來標(biāo)識 URI 所標(biāo)識資源里的某個資源,在 URI 的末尾通過 (#)作為 fragment 的開頭, 其中 # 不屬于 fragment 的值。如https://domain/index#L18這個 URI 中 L18 就是 fragment 的值。大家只需要 知道js通過響應(yīng)瀏覽器地址欄變化的方式能獲取到fragment 就行了。 一般來說,簡化模式用于沒有服務(wù)器端的第三方單頁面應(yīng)用,因?yàn)闆]有服務(wù)器端就無法接收授權(quán)碼。
3.2.5 密碼模式
3.2.5.1 授權(quán)碼模式介紹
密碼模式交互圖:
(1)資源擁有者將用戶名、密碼發(fā)送給客戶端
(2)客戶端拿著資源擁有者的用戶名、密碼向授權(quán)服務(wù)器請求令牌(access_token),請求如下:
http://localhost:8005/oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=%E5%BC%A0%E4%B8%89&password=123參數(shù)列表如下:
-
client_id:客戶端準(zhǔn)入標(biāo)識。
-
client_secret:客戶端秘鑰。
-
grant_type:授權(quán)類型,填寫password表示密碼模式 username:資源擁有者用戶名。
-
password:資源擁有者密碼。
(3)授權(quán)服務(wù)器將令牌(access_token)發(fā)送給client
這種模式十分簡單,但是卻意味著直接將用戶敏感信息泄漏給了client,因此這就說明這種模式只能用于client是我 們自己開發(fā)的情況下。因此密碼模式一般用于我們自己開發(fā)的,第一方原生App或第一方單頁面應(yīng)用。
3.2.5.2 測試
3.2.6 客戶端模式
3.2.6.1 客戶端模式介紹
(1)客戶端向授權(quán)服務(wù)器發(fā)送自己的身份信息,并請求令牌(access_token)
(2)確認(rèn)客戶端身份無誤后,將令牌(access_token)發(fā)送給client,請求如下:
http://localhost:8005/oauth/token?client_id=c1&client_secret=secret&grant_type=client_credentials參數(shù)列表如下:
-
client_id:客戶端準(zhǔn)入標(biāo)識。
-
client_secret:客戶端秘鑰。
-
grant_type:授權(quán)類型,填寫client_credentials表示客戶端模式 這種模式是最方便但最不安全的模式。因此這就要求我們對client完全的信任,而client本身也是安全的。因 此這種模式一般用來提供給我們完全信任的服務(wù)器端服務(wù)。比如,合作方系統(tǒng)對接,拉取一組用戶信息。
3.2.6.2 測試
3.2.7 資源服務(wù)器測試
3.2.7.1 資源服務(wù)器配置
@EnableResourceServer 注解到一個 @Configuration 配置類上,并且必須使用 ResourceServerConfigurer 這個 配置對象來進(jìn)行配置(可以選擇繼承自 ResourceServerConfigurerAdapter 然后覆寫其中的方法,參數(shù)就是這個 對象的實(shí)例),下面是一些可以配置的屬性:
ResourceServerSecurityConfigurer中主要包括:
-
tokenServices:ResourceServerTokenServices 類的實(shí)例,用來實(shí)現(xiàn)令牌服務(wù)。
-
tokenStore:TokenStore類的實(shí)例,指定令牌如何訪問,與tokenServices配置可選
-
resourceId:這個資源服務(wù)的ID,這個屬性是可選的,但是推薦設(shè)置并在授權(quán)服務(wù)中進(jìn)行驗(yàn)證。
-
其他的拓展屬性例如 tokenExtractor 令牌提取器用來提取請求中的令牌。 HttpSecurity配置這個與Spring Security類似:
-
請求匹配器,用來設(shè)置需要進(jìn)行保護(hù)的資源路徑,默認(rèn)的情況下是保護(hù)資源服務(wù)的全部路徑。
-
通過http.authorizeRequests()來設(shè)置受保護(hù)資源的訪問規(guī)則
-
其他的自定義權(quán)限保護(hù)規(guī)則通過 HttpSecurity 來進(jìn)行配置。
@EnableResourceServer 注解自動增加了一個類型為 OAuth2AuthenticationProcessingFilter 的過濾器鏈
編寫ResouceServerConfig:
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter {public static final String RESOURCE_ID = "res1";@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {resources.resourceId(RESOURCE_ID) //資源id.tokenServices(tokenService())//驗(yàn)證令牌的服務(wù).stateless(true);}//資源服務(wù)令牌解析服務(wù)@Beanpublic ResourceServerTokenServices tokenService() { //使用遠(yuǎn)程服務(wù)請求授權(quán)服務(wù)器校驗(yàn)token,必須指定校驗(yàn)token 的url、client_id,client_secretRemoteTokenServices service=new RemoteTokenServices();service.setCheckTokenEndpointUrl("http://localhost:8005/oauth/check_token");service.setClientId("c1");service.setClientSecret("secret");return service;}@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/**").access("#oauth2.hasScope('all')").and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);}}3.2.7.2 驗(yàn)證token
ResourceServerTokenServices 是組成授權(quán)服務(wù)的另一半,如果你的授權(quán)服務(wù)和資源服務(wù)在同一個應(yīng)用程序上的 話,你可以使用 DefaultTokenServices ,這樣的話,你就不用考慮關(guān)于實(shí)現(xiàn)所有必要的接口的一致性問題。如果 你的資源服務(wù)器是分離開的,那么你就必須要確保能夠有匹配授權(quán)服務(wù)提供的 ResourceServerTokenServices,它 知道如何對令牌進(jìn)行解碼。
令牌解析方法: 使用 DefaultTokenServices 在資源服務(wù)器本地配置令牌存儲、解碼、解析方式 使用 RemoteTokenServices 資源服務(wù)器通過 HTTP 請求來解碼令牌,每次都請求授權(quán)服務(wù)器端點(diǎn) /oauth/check_token
使用授權(quán)服務(wù)的 /oauth/check_token 端點(diǎn)你需要在授權(quán)服務(wù)將這個端點(diǎn)暴露出去,以便資源服務(wù)可以進(jìn)行訪問, 這在咱們授權(quán)服務(wù)配置中已經(jīng)提到了,下面是一個例子,在這個例子中,我們在授權(quán)服務(wù)中配置了 /oauth/check_token 和 /oauth/token_key 這兩個端點(diǎn):
?在資源 服務(wù)配置RemoteTokenServices ,在ResouceServerConfig中配置:
@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {resources.resourceId(RESOURCE_ID) //資源id.tokenServices(tokenService())//驗(yàn)證令牌的服務(wù).stateless(true);}//資源服務(wù)令牌解析服務(wù)@Beanpublic ResourceServerTokenServices tokenService() { //使用遠(yuǎn)程服務(wù)請求授權(quán)服務(wù)器校驗(yàn)token,必須指定校驗(yàn)token 的url、client_id,client_secretRemoteTokenServices service=new RemoteTokenServices();service.setCheckTokenEndpointUrl("http://localhost:8005/oauth/check_token");service.setClientId("c1");service.setClientSecret("secret");return service;}3.2.7.3 編寫資源
在controller包下編寫OrderController,此controller表示訂單資源的訪問類:
@RestController public class OrderController {@GetMapping(value = "/r1")@PreAuthorize("hasAnyAuthority('p1')")public String r1() {return "訪問資源1";}}3.2.7.4 添加安全訪問控制
@Configuration @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter {//安全攔截機(jī)制(最重要)@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/r/r1").hasAuthority("p2").antMatchers("/r/r2").hasAuthority("p2").antMatchers("/r/**").authenticated()//所有/r/**的請求必須認(rèn)證通過.anyRequest().permitAll()//除了/r/**,其它的請求可以訪問;} }3.2.7.5 測試
總結(jié)
以上是生活随笔為你收集整理的SpringSecurity OAuth2.0认证授权-part2的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简历,要这样改才能突出重点!!
- 下一篇: Spring原理学习(一):BeanFa