使用Spring Security和OAuth2实现RESTful服务安全认证

使用Spring Security和OAuth2实现RESTful服务安全认证

  

这篇教程是展示如何设置一个OAuth2服务来保护REST资源. 源代码下载github. 你能下载这个源码就开始编写一个被OAuth方法保护的服务。该源码包含功能:

* 用户注册和登录
* Email验证
* Password 丢失

采取的技术有以下:

* OAuth2 Protocol 
* Spring Security 
* Spring Integration 
* Spring Data 
* Jersey/JAX-RS 
* Gradle / Groovy 
* MongoDB

通过以下方式构建项目:

> git clone  [email protected]:iainporter/oauth2-provider.git 
> cd oauth2-provider 
> ./gradlew clean build integrationTest

运行Web项目:

这个应用是基于MongoDB作为持久层,在运行应用之前确认mongod是运行在端口27017.

运行命令:

> ./gradlew tomcatRun

在浏览器打开http://localhost:8080/oauth2-provider/index.html

1. 创建一个用户:

curl -v -X POST \
   -H "Content-Type: application/json" \
   -H "Authorization: Basic MzUzYjMwMmM0NDU3NGY1NjUwNDU2ODdlNTM0ZTdkNmE6Mjg2OTI0Njk3ZTYxNWE2NzJhNjQ2YTQ5MzU0NTY0NmM=" \
   -d '{"user":{"emailAddress":"[email protected]"}, "password":"password"}' \
   'http://localhost:8080/oauth2-provider/v1.0/users'

结果应该是:

{"apiUser":
   {"emailAddress":"[email protected]",
   "firstName":null,
   "lastName":null,
   "age":null,
   "id":"8a34d009-3558-4c8c-a8da-1ad2b2a393c7",
   "name":"[email protected]"},
   "oauth2AccessToken":
   {"access_token":"7e0e4708-7837-4a7e-9f87-81c6429b02ac",
   "token_type":"bearer", 
   "refresh_token":"d0f248ab-e30f-4a85-860c-bd1e388a39b5",
   "expires_in":5183999,
   "scope":"read write"
   }
}

2. 请求一个access token:

curl -v -X POST \
   -H "Content-Type: application/json" \
   -H "Authorization: Basic MzUzYjMwMmM0NDU3NGY1NjUwNDU2ODdlNTM0ZTdkNmE6Mjg2OTI0Njk3ZTYxNWE2NzJhNjQ2YTQ5MzU0NTY0NmM=" \
   'http://localhost:8080/oauth2-provider/oauth/[email protected]&password=password'

结果应该是:

{
  "access_token":"a838780e-35ef-4bd5-92c0-07a45aa74948",
  "token_type":"bearer",
  "refresh_token":"ab06022f-247c-450a-a11e-2ffab116e3dc",
  "expires_in":5183999
}

3. 刷新一个token:

curl -v -X POST \
   -H "Content-Type: application/json" \
   -H "Authorization: Basic MzUzYjMwMmM0NDU3NGY1NjUwNDU2ODdlNTM0ZTdkNmE6Mjg2OTI0Njk3ZTYxNWE2NzJhNjQ2YTQ5MzU0NTY0NmM=" \
   'http://localhost:8080/oauth2-provider/oauth/token?grant_type=refresh_token&refresh_token=ab06022f-247c-450a-a11e-2ffab116e3dc'

结果应该是:

{
   "access_token":"4835cd11-8bb7-4b76-b857-55c6e7f36fc4",
   "token_type":"bearer",
   "refresh_token":"ab06022f-247c-450a-a11e-2ffab116e3dc",
   "expires_in":5183999
}

Web Context

一个Jersey 处理所有资源调用:

  1.   
  2.         jersey-servlet  
  3.         /*  
  4.   

Spring servlet处理所有oauth 调用:

  1.   
  2.         spring  
  3.         /oauth/*  
  4.   

spring security配合定义一个过滤器:

  1.   
  2.     springSecurityFilterChain  
  3.     org.springframework.web.filter.DelegatingFilterProxy  
  4.       
  5.         contextAttribute  
  6.         org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring  
  7.       
  8.   

对根目录下所有url进行 过滤:

  1.   
  2.     springSecurityFilterChain  
  3.     /*  
  4.   

 

配置OAuth 流程

  1.   
  2.           
  3.           
  4.       

缺省的token端点是/oauth/token ,只有 password flow 和刷新 token 支持。

保护token端点

使用Spring security 保护token端点:

  1.       xmlns="http://www.springframework.org/schema/security">  
  2.       
  3.       
  4.       
  5.   

下面配置授权authentication 管理器和客户端服务:

  1.       class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">  
  2.       
  3.   
  4.   
  5.   
  6.       
  7.   
  8.   
  9.   
  10.   
  11.       
  12.   

配置用户授权服务

Resource Owner Password flow 需要管理用户的授权管理器

  1.   
  2.   
  3.   
  4.       
  5.           
  6.       
  7.   

密码 password encoder是用于加密密码。用户服务必须实现一个UserDetailsService ,能根据用户名返回用户。

  1. @Override  
  2. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {  
  3.     notNull(username, "Mandatory argument 'username' missing.");  
  4.     User user = userRepository.findByEmailAddress(username.toLowerCase());  
  5.     if (user == null) {  
  6.         throw new AuthenticationException();  
  7.     }  
  8.     return user;  
  9. }  

配置Token 服务

  1.   
  2.       
  3.       
  4.       
  5.   

保护资源访问

  1.   

核心服务

这个服务提供基于访问token获得用户的信息。URL格式:

/v1.0/users/{id}/someresource 

  1. @Path("/v1.0/me")  
  2. @Component  
  3. @Produces({MediaType.APPLICATION_JSON})  
  4. @Consumes({MediaType.APPLICATION_JSON})  
  5. public class MeResource extends BaseResource {  
  6.   
  7.     @RolesAllowed({"ROLE_USER"})  
  8.     @GET  
  9.     public ApiUser getUser(final @Context SecurityContext securityContext) {  
  10.         User requestingUser = loadUserFromSecurityContext(securityContext);  
  11.         if(requestingUser == null) {  
  12.             throw new UserNotFoundException();  
  13.         }  
  14.         return new ApiUser(requestingUser);  
  15.     }  
  16.   
  17.     protected User loadUserFromSecurityContext(SecurityContext securityContext) {  
  18.         OAuth2Authentication requestingUser = (OAuth2Authentication) securityContext.getUserPrincipal();  
  19.         Object principal = requestingUser.getUserAuthentication().getPrincipal();  
  20.         User user = null;  
  21.         if(principal instanceof User) {  
  22.             user = (User)principal;  
  23.         } else {  
  24.             user = userRepository.findByEmailAddress((String)principal);  
  25.         }  
  26.         return user;  
  27.     }  
  28. }  

测试这个应用,启动:

> ./gradlew tomcatRun

测试:

curl -v -X GET \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer [your token here]" \
  'http://localhost:8080/oauth2-provider/v1.0/me'

 

用户注册 登录授权Java源码

Spring各种源码项目下载

你可能感兴趣的:(RESTFul)