架构师之路-如何构建rest接口的安全性访问(dubbox+oatuh2+rest)

标签: 架构师 rest 接口 | 发表时间:2017-10-12 15:49 | 作者:小开发仔
出处:http://www.iteye.com

建立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来实现管理.

 

参考内容: 从无到有搭建中小型互联网公司后台服务架构与运维架构



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [架构师 rest 接口] 推荐:

架构师之路-如何构建rest接口的安全性访问(dubbox+oatuh2+rest)

- - 企业架构 - ITeye博客
建立oauth2认证需要的数据库及数据表结构. >>前提:  使用Maven来管理项目; spring-security-oauth的版本号为 2.0.10.RELEASE. 添加Maven dependencies; 以下只列出了主要的. web.xml配置; 这一步与只使用Spring Security的配置一样..

关于dubbox部分rest接口超时问题研究

- - 互联网 - ITeye博客
业务高峰期部分rest接口超时有一段时间了,之前一直怀疑是kafka、nginx、log4j、网络等原因并进行优化,一直没有太大改观. 我们生产共有四台nginx反向代理网关,运维在某台nginx中通过日志grep看到,高峰期   nginx反向代理到后端某台tomcat,每秒达到100+,4台nginx则为400+,已超过tomcat设置的并发连接数和完全连接队列的大小(200+100=300).

经典论文 — REST

- ripwu - kernelchina
牛人Roy Thomas Fielding的博士论文,此处可以访问到英文版,中文版可以google一下. HTTP1.0,1.1版本以及URI规范的主要作者,Apache的co-founder. 在写这篇论文之前已经很牛了,笔者不明白的是这种档次牛人还要读博士,文凭有这么重要吗. 文中没有任何令人眼花的数学公式和统计图表,实际上是一篇描述URI,HTTP设计经验教训总结的文章.

MongoDB REST Api介绍

- peigen - NoSQLFan
MongoDB默认会开启一个HTTP协议的端口提供REST的服务,这个端口是你Server端口加上1000,比如你的Server端口为27017,那么这个HTTP端口就是28017,默认的HTTP端口功能是有限的,你可以通过添加–rest参数启动更多功能. 下面是在这个端口通过其RESTFul 的API操作MongoDB数据的几个例子,来源是MongoDB官方文档.

WebSockets与REST之争?

- - 酷勤网-挖经验 [expanded by feedex.net]
WebSockets变得越来越流行并积累了不少用户. 去年年底,WebSockets成为了. W3C的推荐候选,这使得其向标准更迈进了一步. Oracle等其他厂商最近也提交了申请,来启动在Java企业版的下一个版本中引入WebSockets(. JSR 356)的标准流程工作. 绝大部分的主流浏览器,如Chrome、Firefox、Safari和IE,都支持某个WebSockets修正本,并最终会采用最后成形的标准.

REST 与 SOAP巅峰对话

- - CSDN博客互联网推荐文章
随着Restful的流行,soap似乎有点贵族落寞了. 下面我们先详细分析一下他们的各自的特点. REST(Representational State Transfer)是 Roy Fielding 提出的一个描述互联系统架构风格的名词. Web 本质上由各种各样的资源组成,资源由 URI 唯一标识.

为啥REST如此重要?

- - 博客园_知识库
  英文原文: Why REST is so important.   本文我们将讨论 REST,它定义了一组体系架构原则,您可以根据这些原则设计以系统资源为中心的 Web 服务,这是一个非常容易让人误解的概念. 本文主要是写给那些想设计 WebService API 但却对 REST 没有十分清晰认识的开发者们.

REST服务开发实战

- - 互联网 - ITeye博客
本文转自http://kb.cnblogs.com/page/91827/.   如果要说什么是REST的话,那最好先从Web(万维网)说起. 读者可以查看维基百科的词条( http://zh.wikipedia.org/zh-cn/Web),具体的我就不多说了. 总之,Web是我们在互联网上最常用的服务,甚至在某些人的心中,互联网就是Web.

REST API性能比较

- - Java - 编程语言 - ITeye博客
REST已然成为最流行的提供外界服务API的方式. 同时,随着互联网和物联网的普及,如今的应用需要处理大量并发的请求. 因此,开发高性能REST服务已经成为一个成功应用的必备条件. 我这里集中讨论Java和JVM相关技术. 基于Java的REST应用比基于python和ruby的应用往往具备更好的性能.