754
技術社區[雲棲]
架構師之路-如何構建rest接口的安全性訪問(dubbox+oatuh2+rest)
建立oauth2認證需要的數據庫及數據表結構
CREATE SCHEMA IF NOT EXISTS `oauth2` DEFAULT CHARACTER SET utf8 ;
USE `oauth2` ;
-- -----------------------------------------------------
-- Table `oauth2`.`clientdetails`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `oauth2`.`clientdetails` (
`appId` VARCHAR(128) NOT NULL,
`resourceIds` VARCHAR(256) NULL DEFAULT NULL,
`appSecret` VARCHAR(256) NULL DEFAULT NULL,
`scope` VARCHAR(256) NULL DEFAULT NULL,
`grantTypes` VARCHAR(256) NULL DEFAULT NULL,
`redirectUrl` VARCHAR(256) NULL DEFAULT NULL,
`authorities` VARCHAR(256) NULL DEFAULT NULL,
`access_token_validity` INT(11) NULL DEFAULT NULL,
`refresh_token_validity` INT(11) NULL DEFAULT NULL,
`additionalInformation` VARCHAR(4096) NULL DEFAULT NULL,
`autoApproveScopes` VARCHAR(256) NULL DEFAULT NULL,
PRIMARY KEY (`appId`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `oatuh2`.`oauth_access_token`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `oauth2`.`oauth_access_token` (
`token_id` VARCHAR(256) NULL DEFAULT NULL,
`token` BLOB NULL DEFAULT NULL,
`authentication_id` VARCHAR(128) NOT NULL,
`user_name` VARCHAR(256) NULL DEFAULT NULL,
`client_id` VARCHAR(256) NULL DEFAULT NULL,
`authentication` BLOB NULL DEFAULT NULL,
`refresh_token` VARCHAR(256) NULL DEFAULT NULL,
PRIMARY KEY (`authentication_id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `oatuh2`.`oauth_approvals`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `oauth2`.`oauth_approvals` (
`userId` VARCHAR(256) NULL DEFAULT NULL,
`clientId` VARCHAR(256) NULL DEFAULT NULL,
`scope` VARCHAR(256) NULL DEFAULT NULL,
`status` VARCHAR(10) NULL DEFAULT NULL,
`expiresAt` DATETIME NULL DEFAULT NULL,
`lastModifiedAt` DATETIME NULL DEFAULT NULL)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `oatuh2`.`oauth_client_details`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `oauth2`.`oauth_client_details` (
`client_id` VARCHAR(128) NOT NULL,
`resource_ids` VARCHAR(256) NULL DEFAULT NULL,
`client_secret` VARCHAR(256) NULL DEFAULT NULL,
`scope` VARCHAR(256) NULL DEFAULT NULL,
`authorized_grant_types` VARCHAR(256) NULL DEFAULT NULL,
`web_server_redirect_uri` VARCHAR(256) NULL DEFAULT NULL,
`authorities` VARCHAR(256) NULL DEFAULT NULL,
`access_token_validity` INT(11) NULL DEFAULT NULL,
`refresh_token_validity` INT(11) NULL DEFAULT NULL,
`additional_information` VARCHAR(4096) NULL DEFAULT NULL,
`autoapprove` VARCHAR(256) NULL DEFAULT NULL,
PRIMARY KEY (`client_id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `oatuh2`.`oauth_client_token`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `oauth2`.`oauth_client_token` (
`token_id` VARCHAR(256) NULL DEFAULT NULL,
`token` BLOB NULL DEFAULT NULL,
`authentication_id` VARCHAR(128) NOT NULL,
`user_name` VARCHAR(256) NULL DEFAULT NULL,
`client_id` VARCHAR(256) NULL DEFAULT NULL,
PRIMARY KEY (`authentication_id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `oatuh2`.`oauth_code`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `oauth2`.`oauth_code` (
`code` VARCHAR(256) NULL DEFAULT NULL,
`authentication` BLOB NULL DEFAULT NULL)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `oatuh2`.`oauth_refresh_token`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `oauth2`.`oauth_refresh_token` (
`token_id` VARCHAR(256) NULL DEFAULT NULL,
`token` BLOB NULL DEFAULT NULL,
`authentication` BLOB NULL DEFAULT NULL)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
>>前提: 使用Maven來管理項目; spring-security-oauth的版本號為 2.0.10.RELEASE
1. 添加Maven dependencies; 以下隻列出了主要的
-
-
<dependency>
-
<groupId>org.springframework.securitygroupId>
-
<artifactId>spring-security-coreartifactId>
-
<version>${spring.security.version}version>
-
dependency>
-
<dependency>
-
<groupId>org.springframework.securitygroupId>
-
<artifactId>spring-security-webartifactId>
-
<version>${spring.security.version}version>
-
dependency>
-
<dependency>
-
<groupId>org.springframework.securitygroupId>
-
<artifactId>spring-security-taglibsartifactId>
-
<version>${spring.security.version}version>
-
dependency>
-
<dependency>
-
<groupId>org.springframework.securitygroupId>
-
<artifactId>spring-security-aclartifactId>
-
<version>${spring.security.version}version>
-
dependency>
-
<dependency>
-
<groupId>org.springframework.securitygroupId>
-
<artifactId>spring-security-cryptoartifactId>
-
<version>${spring.security.version}version>
-
dependency>
-
<dependency>
-
<groupId>org.springframework.securitygroupId>
-
<artifactId>spring-security-configartifactId>
-
<version>${spring.security.version}version>
-
dependency>
-
-
<dependency>
-
<groupId>org.springframework.security.oauthgroupId>
-
<artifactId>spring-security-oauth2artifactId>
-
<version>1.0.5.RELEASEversion>
-
dependency>
2. web.xml配置; 這一步與隻使用Spring Security的配置一樣.
-
pre><pre code_snippet_id="73897" snippet_file_name="blog_20131119_2_2257675" name="code" class="html"> <filter>
-
<filter-name>springSecurityFilterChainfilter-name>
-
<filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
-
filter>
-
-
<filter-mapping>
-
<filter-name>springSecurityFilterChainfilter-name>
-
<url-pattern>/*url-pattern>
-
filter-mapping>
-
-
-
<context-param>
-
<param-name>contextConfigLocationparam-name>
-
<param-value>classpath:spring/*.xmlparam-value>
-
context-param>
-
-
-
<listener>
-
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
-
listener>
-
-
-
<servlet>
-
<servlet-name>hyservlet-name>
-
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
-
<load-on-startup>2load-on-startup>
-
servlet>
-
<servlet-mapping>
-
<servlet-name>hyservlet-name>
-
<url-pattern>/url-pattern>
-
servlet-mapping>
對於Spring MVC, 需要配置文件hy-servlet.xml, 該文件不是這兒關注的(忽略);
在classpath創建spring目錄, 在該目錄裏創建 security.xml 文件, 這是所有步驟配置的重點.
3.security.xml的配置; 重點開始.
3.1 起用注解; TokenEndpoint與AuthorizationEndpoint需要
-
<mvc:annotation-driven/>
-
<mvc:default-servlet-handler/>
3.2 TokenServices 配置
1). TokenStore, 使用JdbcTokenStore, 將token信息存放數據庫, 需要提供一個dataSource對象; 也可使用InMemoryTokenStore存於內存中
-
-
<beans:bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.JdbcTokenStore">
-
<beans:constructor-arg index="0" ref="dataSource"/>
-
beans:bean>
注: 可以在spring-security-oauth2中找到對應的SQL腳本, 地址為https://github.com/spring-projects/spring-security-oauth/tree/master/spring-security-oauth2/src/test/resources, 目錄中的schema.sql 即是. (以下不再說明SQL腳本的問題)
2).TokenServices; 需要注入TokenStore
-
<beans:bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
-
<beans:property name="tokenStore" ref="tokenStore"/>
-
<beans:property name="supportRefreshToken" value="true"/>
-
beans:bean>
如果允許刷新token 請將supportRefreshToken 的值設置為true, 默認為不允許
3.3 ClientDetailsService 配置, 使用JdbcClientDetailsService, 也需要提供dataSource, 替換demo中直接配置在配置文件中
-
<beans:bean id="clientDetailsService" class="org.springframework.security.oauth2.provider.JdbcClientDetailsService">
-
<beans:constructor-arg index="0" ref="dataSource"/>
-
beans:bean>
3.4 ClientDetailsUserDetailsService配置, 該類實現了Spring security中 UserDetailsService 接口
-
<beans:bean id="oauth2ClientDetailsUserService"
-
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
-
<beans:constructor-arg ref="clientDetailsService"/>
-
beans:bean>
3.5 OAuth2AuthenticationEntryPoint配置
-
<beans:bean id="oauth2AuthenticationEntryPoint"
-
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"/>
3.6 oauth2 AuthenticationManager配置; 在整個配置中,有兩個AuthenticationManager需要配置
-
<authentication-manager id="oauth2AuthenticationManager">
-
<authentication-provider user-service-ref="oauth2ClientDetailsUserService"/>
-
authentication-manager>
第二個AuthenticationManager用於向獲取UserDetails信息,
-
<authentication-manager alias="authenticationManager">
-
<authentication-provider user-service-ref="userService">
-
<password-encoder hash="md5"/>
-
authentication-provider>
-
authentication-manager>
userService是一個實現UserDetailsService的Bean
3.7 OAuth2AccessDeniedHandler配置, 實現AccessDeniedHandler接口
-
<beans:bean id="oauth2AccessDeniedHandler"
-
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
3.8 UserApprovalHandler配置, 這兒使用DefaultUserApprovalHandler, 這裏是實現client是否可信任的關鍵點,你可以擴展該接口來自定義approval行為
-
<beans:bean id="oauthUserApprovalHandler" class="org.springframework.security.oauth2.provider.approval.DefaultUserApprovalHandler">
-
beans:bean>
3.9 authorization-server配置, 核心
-
<oauth2:authorization-server client-details-service-ref="clientDetailsService" token-services-ref="tokenServices"
-
user-approval-handler-ref="oauthUserApprovalHandler">
-
<oauth2:authorization-code/>
-
<oauth2:implicit/>
-
<oauth2:refresh-token/>
-
<oauth2:client-credentials/>
-
<oauth2:password/>
-
oauth2:authorization-server>
該元素裏麵的每個標簽可設置每一種authorized-grant-type的行為. 如disable refresh-token的配置為
-
<oauth2:refresh-token disabled="true"/>
3.10 Oauth2 AccessDecisionManager配置, 這兒在默認的Spring Security AccessDecisionManager的基礎上添加了ScopeVoter
-
<beans:bean id="oauth2AccessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
-
<beans:constructor-arg>
-
<beans:list>
-
<beans:bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
-
<beans:bean class="org.springframework.security.access.vote.RoleVoter"/>
-
<beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
-
beans:list>
-
beans:constructor-arg>
-
beans:bean>
3.11 resource-server配置, 這兒定義兩咱不同的resource
-
-
<oauth2:resource-server id="unityResourceServer" resource-id="unity-resource" token-services-ref="tokenServices"/>
-
-
-
<oauth2:resource-server id="mobileResourceServer" resource-id="mobile-resource" token-services-ref="tokenServices"/>
注意: 每個resource-id的值必須在對應的ClientDetails中resourceIds值中存在
3.12 ClientCredentialsTokenEndpointFilter配置, 該Filter將作用於Spring Security的chain 鏈條中
-
<beans:bean id="clientCredentialsTokenEndpointFilter"
-
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
-
<beans:property name="authenticationManager" ref="oauth2AuthenticationManager"/>
-
beans:bean>
3.13 /oauth/token 的http 配置, 用於監聽該URL的請求, 核心
-
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="oauth2AuthenticationManager"
-
entry-point-ref="oauth2AuthenticationEntryPoint">
-
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
-
<anonymous enabled="false"/>
-
<http-basic entry-point-ref="oauth2AuthenticationEntryPoint"/>
-
-
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER"/>
-
<access-denied-handler ref="oauth2AccessDeniedHandler"/>
-
http>
3.14 針對不同resource的http配置, 由於上麵配置了兩個resource, 這兒也配置兩個
-
-
<http pattern="/unity/**" create-session="never" entry-point-ref="oauth2AuthenticationEntryPoint"
-
access-decision-manager-ref="oauth2AccessDecisionManager">
-
<anonymous enabled="false"/>
-
-
<intercept-url pattern="/unity/**" access="ROLE_UNITY,SCOPE_READ"/>
-
-
<custom-filter ref="unityResourceServer" before="PRE_AUTH_FILTER"/>
-
<access-denied-handler ref="oauth2AccessDeniedHandler"/>
-
http>
-
-
-
<http pattern="/m/**" create-session="never" entry-point-ref="oauth2AuthenticationEntryPoint"
-
access-decision-manager-ref="oauth2AccessDecisionManager">
-
<anonymous enabled="false"/>
-
-
<intercept-url pattern="/m/**" access="ROLE_MOBILE,SCOPE_READ"/>
-
-
<custom-filter ref="mobileResourceServer" before="PRE_AUTH_FILTER"/>
-
<access-denied-handler ref="oauth2AccessDeniedHandler"/>
-
http>
注意每一個http對應不同的resourceServer. access-decison-manager-ref對應Oauth的AccessDecisionManager
3.15 默認的http配置,給/oauth/** 設置權限
-
<http access-denied-page="/login.jsp?authorization_error=2" disable-url-rewriting="true"
-
authentication-manager-ref="authenticationManager">
-
<intercept-url pattern="/oauth/**" access="ROLE_USER,ROLE_UNITY,ROLE_MOBILE"/>
-
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
-
-
<form-login authentication-failure-url="/login.jsp?authentication_error=1" default-target-url="/index.jsp"
-
login-page="/login.jsp" login-processing-url="/login.do"/>
-
<logout logout-success-url="/index.jsp" logout-url="/logout.do"/>
-
<anonymous/>
-
http>
到此, securiy.xml 配置完畢.
當然,還有些額外的工作你需要做, 如配置dataSource, 創建數據庫, 添加用戶用戶信息, 管理ClientDetails等等.
Oauth相關的數據都是存放在數據庫, 我們就可以根據表結果創建domain來實現管理.
最後更新:2017-10-12 15:34:04