Secure Spring REST API using OAuth2

来源:互联网 发布:性别就业歧视现状数据 编辑:程序博客网 时间:2024/05/23 15:55

http://websystique.com/spring-security/secure-spring-rest-api-using-oauth2/

Secure Spring REST API using OAuth2

Let’s secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a REST API using Spring OAuth2. Our use-case fits well with Resource-owner Password Grant flow of OAUth2 specification. We will use two different clients [Postman and a Spring RestTemplate based java application] to access our OAuth2 protected REST resources.

If you are already familiar with OAuth2 concepts, you may want to skip the theory, and jump right into code. As always, complete code can be found in attachment at the end of this article. Let’s get started.


Other interesting posts you may like

  • Spring Boot+AngularJS+Spring Data+Hibernate+MySQL CRUD App
  • Spring Boot REST API Tutorial
  • Spring Boot WAR deployment example
  • Spring Boot Introduction + Hello World Example
  • AngularJS+Spring Security using Basic Authentication
  • Secure Spring REST API using Basic Authentication

What is OAuth2

OAuth2 is an standardized authorization protocol/framework. As per Official OAuth2 Specification:

The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf.

Big players like Google, Facebook and others are already using their own OAuth2 implementations for quite some time. Enterprises too are moving fast towards OAuth2 adoption.

I found OAuth2 specification rather simple to follow. Yet if you want to start even quickly, an excellent article on OAuth2 fundamentals can be found here which gives a deep insight in OAUth2 theoretical concepts.

Spring Security OAuth project provides all the necessary API we might need in order to develop an OAuth2 compliant implementation using Spring. Official Spring security oauth project provides a comprehensive example for implementing OAuth2. The code samples of this post is inspired by that examples itself. The intention of this post is to just use bare-minimum functionality required in order to secure our REST API, nothing more.

At minimum, you should be aware of four key concepts in OAuth2:

1. OAuth2 Roles

OAuth2 defines four roles:

  • resource owner:
    Could be you. An entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an end-user.
  • resource server:
    The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.
  • client:
    An application making protected resource requests on behalf of the resource owner and with its authorization. It could be a mobile app asking your permission to access your Facebook feeds, a REST client trying to access REST API, a web site [Stackoverflow e.g.] providing an alternative login option using Facebook account.
  • authorization server:
    The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization.

In our example, our REST API can only be accessed via Resource server which will require an access token to be present with request

2. OAuth2 Authorization Grant types

An authorization grant is a credential representing the resource owner’s authorization (to access its protected resources) used by the client to obtain an access token. The specification defines four grant types:

  • authorization code
  • implicit
  • resource owner password credentials
  • client credentials

We will be using resource owner password credentials grant type. The reason is simple, we are not implementing a view which redirects us to a login page. Only the usage where a client [Postman or RestTemplate based Java client e.g.] have the Resource owner’s credentials and they provide those credential [along with client credentials] to authorization server in order to eventually receive the access-token[and optionally refresh token], and then use that token to actually access the resources.

A common example is the GMail app [a client] on your smartphone which takes your credentials and use them to connect to GMail servers. It also shows that ‘Password Credentials Grant’ is best suited when both the client and the servers are from same company as the trust is there, you don’t want to provide your credentials to a third party.

3. OAuth2 Tokens

Tokens are implementation specific random strings, generated by the authorization server and are issued when the client requests them.

  • Access Token : Sent with each request, usually valid for a very short life time [an hour e.g.]
  • Refresh Token : Mainly used to get a new access token, not sent with each request, usually lives longer than access token.
A Word on HTTPS : For any sort of Security implementation, ranging from Basic authentication to a full fledged OAuth2 implementation, HTTPS is a must have. Without HTTPS, no matter what your implementation is, security is vulnerable to be compromised.

4. OAuth2 Access Token Scope

Client can ask for the resource with specific access rights using scope [want to access feeds & photos of this users facebook account], and authorization server in turn return scope showing what access rights were actually granted to the client [Resource owner only allowed feeds access, no photos e.g.].


Let’s Get into Code

Let’s implement the necessary building blocks to implement OAuth using Spring Security, in order to access our REST resources.

1. Resource Server

Resource Server hosts the resources [our REST API] the client is interested in. Resources are located on /user/.@EnableResourceServer annotation, applied on OAuth2 Resource Servers, enables a Spring Security filter that authenticates requests using an incoming OAuth2 token. Class ResourceServerConfigurerAdapter implementsResourceServerConfigurer providing methods to adjust the access rules and paths that are protected by OAuth2 security.

packagecom.websystique.springmvc.security;
 
importorg.springframework.context.annotation.Configuration;
importorg.springframework.security.config.annotation.web.builders.HttpSecurity;
importorg.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
importorg.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
importorg.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
importorg.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
 
@Configuration
@EnableResourceServer
publicclass ResourceServerConfiguration extendsResourceServerConfigurerAdapter {
 
    privatestatic final String RESOURCE_ID = "my_rest_api";
     
    @Override
    publicvoid configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID).stateless(false);
    }
 
    @Override
    publicvoid configure(HttpSecurity http) throwsException {
        http.
        anonymous().disable()
        .requestMatchers().antMatchers("/user/**")
        .and().authorizeRequests()
        .antMatchers("/user/**").access("hasRole('ADMIN')")
        .and().exceptionHandling().accessDeniedHandler(newOAuth2AccessDeniedHandler());
    }
 
}

2. Authorization Server

Authorization server is the one responsible for verifying credentials and if credentials are OK, providing the tokens[refresh-token as well as access-token]. It also contains information about registered clients and possible access scopes and grant types. The token store is used to store the token. We will be using an in-memory token store.@EnableAuthorizationServer enables an Authorization Server (i.e. an AuthorizationEndpoint and a TokenEndpoint) in the current application context. Class AuthorizationServerConfigurerAdapter implementsAuthorizationServerConfigurer which provides all the necessary methods to configure an Authorization server.

packagecom.websystique.springmvc.security;
 
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.security.authentication.AuthenticationManager;
importorg.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
importorg.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
importorg.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
importorg.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
importorg.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
importorg.springframework.security.oauth2.provider.approval.UserApprovalHandler;
importorg.springframework.security.oauth2.provider.token.TokenStore;
 
@Configuration
@EnableAuthorizationServer
publicclass AuthorizationServerConfiguration extendsAuthorizationServerConfigurerAdapter {
 
    privatestatic String REALM="MY_OAUTH_REALM";
     
    @Autowired
    privateTokenStore tokenStore;
 
    @Autowired
    privateUserApprovalHandler userApprovalHandler;
 
    @Autowired
    @Qualifier("authenticationManagerBean")
    privateAuthenticationManager authenticationManager;
 
    @Override
    publicvoid configure(ClientDetailsServiceConfigurer clients) throwsException {
 
        clients.inMemory()
            .withClient("my-trusted-client")
            .authorizedGrantTypes("password","authorization_code","refresh_token","implicit")
            .authorities("ROLE_CLIENT","ROLE_TRUSTED_CLIENT")
            .scopes("read","write","trust")
            .secret("secret")
            .accessTokenValiditySeconds(120).//Access token is only valid for 2 minutes.
            refreshTokenValiditySeconds(600);//Refresh token is only valid for 10 minutes.
    }
 
    @Override
    publicvoid configure(AuthorizationServerEndpointsConfigurer endpoints) throwsException {
        endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
                .authenticationManager(authenticationManager);
    }
 
    @Override
    publicvoid configure(AuthorizationServerSecurityConfigurer oauthServer) throwsException {
        oauthServer.realm(REALM+"/client");
    }
 
}

Above configuration

  • Registers a client with client-id ‘my-trusted-client’ and password ‘secret’ and roles & scope he is allowed for.
  • Specifies that any generated access token will be valid for only 120 seconds
  • Specifies that any generated refresh token will be valid for only 600 seconds

3. Security Configuration

Gluing everything together. Endpoint /oauth/token is used to request a token [access or refresh]. Resource owners [bill,bob] are configured here itself.

packagecom.websystique.springmvc.security;
 
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.security.authentication.AuthenticationManager;
importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
importorg.springframework.security.config.annotation.web.builders.HttpSecurity;
importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
importorg.springframework.security.oauth2.provider.ClientDetailsService;
importorg.springframework.security.oauth2.provider.approval.ApprovalStore;
importorg.springframework.security.oauth2.provider.approval.TokenApprovalStore;
importorg.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
importorg.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
importorg.springframework.security.oauth2.provider.token.TokenStore;
importorg.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
 
@Configuration
@EnableWebSecurity
publicclass OAuth2SecurityConfiguration extendsWebSecurityConfigurerAdapter {
 
    @Autowired
    privateClientDetailsService clientDetailsService;
     
    @Autowired
    publicvoid globalUserDetails(AuthenticationManagerBuilder auth) throwsException {
        auth.inMemoryAuthentication()
        .withUser("bill").password("abc123").roles("ADMIN").and()
        .withUser("bob").password("abc123").roles("USER");
    }
 
    @Override
    protectedvoid configure(HttpSecurity http) throwsException {
        http
        .csrf().disable()
        .anonymous().disable()
        .authorizeRequests()
        .antMatchers("/oauth/token").permitAll();
    }
 
    @Override
    @Bean
    publicAuthenticationManager authenticationManagerBean() throwsException {
        returnsuper.authenticationManagerBean();
    }
 
 
    @Bean
    publicTokenStore tokenStore() {
        returnnew InMemoryTokenStore();
    }
 
    @Bean
    @Autowired
    publicTokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
        TokenStoreUserApprovalHandler handler = newTokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(newDefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        returnhandler;
    }
     
    @Bean
    @Autowired
    publicApprovalStore approvalStore(TokenStore tokenStore) throwsException {
        TokenApprovalStore store = newTokenApprovalStore();
        store.setTokenStore(tokenStore);
        returnstore;
    }
     
}

Additionally, enable Global method security which will activate @PreFilter, @PostFilter, @PreAuthorize @PostAuthorize annotations if we want to use them.

packagecom.websystique.springmvc.security;
 
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
importorg.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
importorg.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
importorg.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler;
 
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
publicclass MethodSecurityConfig extendsGlobalMethodSecurityConfiguration {
    @Autowired
    privateOAuth2SecurityConfiguration securityConfig;
 
    @Override
    protectedMethodSecurityExpressionHandler createExpressionHandler() {
        returnnew OAuth2MethodSecurityExpressionHandler();
    }
}

4. Endpoints and their purpose

  • Attempt to access resources [REST API] without any authorization [will fail of-course].
    GET http://localhost:8080/SpringSecurityOAuth2Example/user/
  • Ask for tokens[access+refresh] using HTTP POST on /oauth/token, with grant_type=password,and resource owners credentials as req-params. Additionally, send client credentials in Authorization header.

    POST http://localhost:8080/SpringSecurityOAuth2Example/oauth/token?grant_type=password&username=bill&password=abc123

  • Ask for a new access token via valid refresh-token, using HTTP POST on /oauth/token, with grant_type=refresh_token,and sending actual refresh token. Additionally, send client credentials in Authorization header.

    POST http://localhost:8080/SpringSecurityOAuth2Example/oauth/token?grant_type=refresh_token&refresh_token=094b7d23-973f-4cc1-83ad-8ffd43de1845

  • Access the resource by providing an access token using access_token query param with request.
    GET http://localhost:8080/SpringSecurityOAuth2Example/user/?access_token=3525d0e4-d881-49e7-9f91-bcfd18259109

5. Rest API

The simple Spring REST API i used in most of my posts.

packagecom.websystique.springmvc.controller;
  
importjava.util.List;
  
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.http.HttpHeaders;
importorg.springframework.http.HttpStatus;
importorg.springframework.http.MediaType;
importorg.springframework.http.ResponseEntity;
importorg.springframework.web.bind.annotation.PathVariable;
importorg.springframework.web.bind.annotation.RequestBody;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.bind.annotation.RestController;
importorg.springframework.web.util.UriComponentsBuilder;
  
importcom.websystique.springmvc.model.User;
importcom.websystique.springmvc.service.UserService;
  
@RestController
publicclass HelloWorldRestController {
  
    @Autowired
    UserService userService;  //Service which will do all data retrieval/manipulation work
  
      
    //-------------------Retrieve All Users--------------------------------------------------------
      
    @RequestMapping(value = "/user/", method = RequestMethod.GET)
    publicResponseEntity<List<User>> listAllUsers() {
        List<User> users = userService.findAllUsers();
        if(users.isEmpty()){
            returnnew ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
        }
        returnnew ResponseEntity<List<User>>(users, HttpStatus.OK);
    }
  
  
    //-------------------Retrieve Single User--------------------------------------------------------
      
    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE,MediaType.APPLICATION_XML_VALUE})
    publicResponseEntity<User> getUser(@PathVariable("id")longid) {
        System.out.println("Fetching User with id " + id);
        User user = userService.findById(id);
        if(user == null) {
            System.out.println("User with id " + id + " not found");
            returnnew ResponseEntity<User>(HttpStatus.NOT_FOUND);
        }
        returnnew ResponseEntity<User>(user, HttpStatus.OK);
    }
  
      
      
    //-------------------Create a User--------------------------------------------------------
      
    @RequestMapping(value = "/user/", method = RequestMethod.POST)
    publicResponseEntity<Void> createUser(@RequestBodyUser user, UriComponentsBuilder ucBuilder) {
        System.out.println("Creating User " + user.getName());
  
        if(userService.isUserExist(user)) {
            System.out.println("A User with name " + user.getName() + " already exist");
            returnnew ResponseEntity<Void>(HttpStatus.CONFLICT);
        }
  
        userService.saveUser(user);
  
        HttpHeaders headers = newHttpHeaders();
        headers.setLocation(ucBuilder.path("/user/{id}").buildAndExpand(user.getId()).toUri());
        returnnew ResponseEntity<Void>(headers, HttpStatus.CREATED);
    }
  
      
    //------------------- Update a User --------------------------------------------------------
      
    @RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
    publicResponseEntity<User> updateUser(@PathVariable("id")longid, @RequestBodyUser user) {
        System.out.println("Updating User " + id);
          
        User currentUser = userService.findById(id);
          
        if(currentUser==null) {
            System.out.println("User with id " + id + " not found");
            returnnew ResponseEntity<User>(HttpStatus.NOT_FOUND);
        }
  
        currentUser.setName(user.getName());
        currentUser.setAge(user.getAge());
        currentUser.setSalary(user.getSalary());
          
        userService.updateUser(currentUser);
        returnnew ResponseEntity<User>(currentUser, HttpStatus.OK);
    }
  
    //------------------- Delete a User --------------------------------------------------------
      
    @RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
    publicResponseEntity<User> deleteUser(@PathVariable("id")longid) {
        System.out.println("Fetching & Deleting User with id " + id);
  
        User user = userService.findById(id);
        if(user == null) {
            System.out.println("Unable to delete. User with id " + id + " not found");
            returnnew ResponseEntity<User>(HttpStatus.NOT_FOUND);
        }
  
        userService.deleteUserById(id);
        returnnew ResponseEntity<User>(HttpStatus.NO_CONTENT);
    }
  
      
    //------------------- Delete All Users --------------------------------------------------------
      
    @RequestMapping(value = "/user/", method = RequestMethod.DELETE)
    publicResponseEntity<User> deleteAllUsers() {
        System.out.println("Deleting All Users");
  
        userService.deleteAllUsers();
        returnnew ResponseEntity<User>(HttpStatus.NO_CONTENT);
    }
  
}

6. Running the application

Run it and test it using two different clients.

Client 1: Postman

Try to access a resource without any auth info, wil get a 401.

SpringOAuth2_img1

Let’s get the tokens. First add an authorization header with client credentials [my-trusted-client/secret].

SpringOAuth2_img2

Click on update request, verify the header in header-tab.

SpringOAuth2_img3

Send the Post request, you should receive the response containing access-token as well as refresh-token.

SpringOAuth2_img4

Save these tokens somewhere, you will need them. Now you can use this access-token [valid for 2 minutes] to access resources.

SpringOAuth2_img5

After 2 minutes, access-token gets expired, your further resource requests will fail.

SpringOAuth2_img6

We need a new access-token. Fire a post to with refresh-token to get a brand-new access-token.

SpringOAuth2_img7

Use this new access-token to access the resources.

SpringOAuth2_img8

Refresh-token expires too[10 minutes]. After that, you should see your refresh request getting failed.

SpringOAuth2_img9

It means you need to request a new refresh+access-token, as in step 2.

Client 2: RestTemplate based java application

Method sendTokenRequest is used to actually get the tokens. The access-token we got in response is then used with each request. If required, You can implement the refresh-token flow easily in below example.

packagecom.websystique.springmvc;
  
importjava.net.URI;
importjava.util.Arrays;
importjava.util.LinkedHashMap;
importjava.util.List;
 
importorg.apache.commons.codec.binary.Base64;
importorg.springframework.http.HttpEntity;
importorg.springframework.http.HttpHeaders;
importorg.springframework.http.HttpMethod;
importorg.springframework.http.MediaType;
importorg.springframework.http.ResponseEntity;
importorg.springframework.util.Assert;
importorg.springframework.web.client.RestTemplate;
 
importcom.websystique.springmvc.model.AuthTokenInfo;
importcom.websystique.springmvc.model.User;
  
publicclass SpringRestClient {
  
    publicstatic final String REST_SERVICE_URI = "http://localhost:8080/SpringSecurityOAuth2Example";
     
    publicstatic final String AUTH_SERVER_URI = "http://localhost:8080/SpringSecurityOAuth2Example/oauth/token";
     
    publicstatic final String QPM_PASSWORD_GRANT = "?grant_type=password&username=bill&password=abc123";
     
    publicstatic final String QPM_ACCESS_TOKEN = "?access_token=";
 
    /*
     * Prepare HTTP Headers.
     */
    privatestatic HttpHeaders getHeaders(){
        HttpHeaders headers = newHttpHeaders();
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        returnheaders;
    }
     
    /*
     * Add HTTP Authorization header, using Basic-Authentication to send client-credentials.
     */
    privatestatic HttpHeaders getHeadersWithClientCredentials(){
        String plainClientCredentials="my-trusted-client:secret";
        String base64ClientCredentials = newString(Base64.encodeBase64(plainClientCredentials.getBytes()));
         
        HttpHeaders headers = getHeaders();
        headers.add("Authorization","Basic " + base64ClientCredentials);
        returnheaders;
    }   
     
    /*
     * Send a POST request [on /oauth/token] to get an access-token, which will then be send with each request.
     */
    @SuppressWarnings({"unchecked"})
    privatestatic AuthTokenInfo sendTokenRequest(){
        RestTemplate restTemplate = newRestTemplate();
         
        HttpEntity<String> request = newHttpEntity<String>(getHeadersWithClientCredentials());
        ResponseEntity<Object> response = restTemplate.exchange(AUTH_SERVER_URI+QPM_PASSWORD_GRANT, HttpMethod.POST, request, Object.class);
        LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>)response.getBody();
        AuthTokenInfo tokenInfo = null;
         
        if(map!=null){
            tokenInfo = newAuthTokenInfo();
            tokenInfo.setAccess_token((String)map.get("access_token"));
            tokenInfo.setToken_type((String)map.get("token_type"));
            tokenInfo.setRefresh_token((String)map.get("refresh_token"));
            tokenInfo.setExpires_in((int)map.get("expires_in"));
            tokenInfo.setScope((String)map.get("scope"));
            System.out.println(tokenInfo);
            //System.out.println("access_token ="+map.get("access_token")+", token_type="+map.get("token_type")+", refresh_token="+map.get("refresh_token")
            //+", expires_in="+map.get("expires_in")+", scope="+map.get("scope"));;
        }else{
            System.out.println("No user exist----------");
             
        }
        returntokenInfo;
    }
     
    /*
     * Send a GET request to get list of all users.
     */
    @SuppressWarnings({"unchecked","rawtypes"})
    privatestatic void listAllUsers(AuthTokenInfo tokenInfo){
        Assert.notNull(tokenInfo,"Authenticate first please......");
 
        System.out.println("\nTesting listAllUsers API-----------");
        RestTemplate restTemplate = newRestTemplate();
         
        HttpEntity<String> request = newHttpEntity<String>(getHeaders());
        ResponseEntity<List> response = restTemplate.exchange(REST_SERVICE_URI+"/user/"+QPM_ACCESS_TOKEN+tokenInfo.getAccess_token(),
                HttpMethod.GET, request, List.class);
        List<LinkedHashMap<String, Object>> usersMap = (List<LinkedHashMap<String, Object>>)response.getBody();
         
        if(usersMap!=null){
            for(LinkedHashMap<String, Object> map : usersMap){
                System.out.println("User : id="+map.get("id")+", Name="+map.get("name")+", Age="+map.get("age")+", Salary="+map.get("salary"));;
            }
        }else{
            System.out.println("No user exist----------");
        }
    }
      
    /*
     * Send a GET request to get a specific user.
     */
    privatestatic void getUser(AuthTokenInfo tokenInfo){
        Assert.notNull(tokenInfo,"Authenticate first please......");
        System.out.println("\nTesting getUser API----------");
        RestTemplate restTemplate = newRestTemplate();
        HttpEntity<String> request = newHttpEntity<String>(getHeaders());
        ResponseEntity<User> response = restTemplate.exchange(REST_SERVICE_URI+"/user/1"+QPM_ACCESS_TOKEN+tokenInfo.getAccess_token(),
                HttpMethod.GET, request, User.class);
        User user = response.getBody();
        System.out.println(user);
    }
      
    /*
     * Send a POST request to create a new user.
     */
    privatestatic void createUser(AuthTokenInfo tokenInfo) {
        Assert.notNull(tokenInfo,"Authenticate first please......");
        System.out.println("\nTesting create User API----------");
        RestTemplate restTemplate = newRestTemplate();
        User user = newUser(0,"Sarah",51,134);
        HttpEntity<Object> request = newHttpEntity<Object>(user, getHeaders());
        URI uri = restTemplate.postForLocation(REST_SERVICE_URI+"/user/"+QPM_ACCESS_TOKEN+tokenInfo.getAccess_token(),
                request, User.class);
        System.out.println("Location : "+uri.toASCIIString());
    }
  
    /*
     * Send a PUT request to update an existing user.
     */
    privatestatic void updateUser(AuthTokenInfo tokenInfo) {
        Assert.notNull(tokenInfo,"Authenticate first please......");
        System.out.println("\nTesting update User API----------");
        RestTemplate restTemplate = newRestTemplate();
        User user  = newUser(1,"Tomy",33,70000);
        HttpEntity<Object> request = newHttpEntity<Object>(user, getHeaders());
        ResponseEntity<User> response = restTemplate.exchange(REST_SERVICE_URI+"/user/1"+QPM_ACCESS_TOKEN+tokenInfo.getAccess_token(),
                HttpMethod.PUT, request, User.class);
        System.out.println(response.getBody());
    }
  
    /*
     * Send a DELETE request to delete a specific user.
     */
    privatestatic void deleteUser(AuthTokenInfo tokenInfo) {
        Assert.notNull(tokenInfo,"Authenticate first please......");
        System.out.println("\nTesting delete User API----------");
        RestTemplate restTemplate = newRestTemplate();
        HttpEntity<String> request = newHttpEntity<String>(getHeaders());
        restTemplate.exchange(REST_SERVICE_URI+"/user/3"+QPM_ACCESS_TOKEN+tokenInfo.getAccess_token(),
                HttpMethod.DELETE, request, User.class);
    }
  
  
    /*
     * Send a DELETE request to delete all users.
     */
    privatestatic void deleteAllUsers(AuthTokenInfo tokenInfo) {
        Assert.notNull(tokenInfo,"Authenticate first please......");
        System.out.println("\nTesting all delete Users API----------");
        RestTemplate restTemplate = newRestTemplate();
        HttpEntity<String> request = newHttpEntity<String>(getHeaders());
        restTemplate.exchange(REST_SERVICE_URI+"/user/"+QPM_ACCESS_TOKEN+tokenInfo.getAccess_token(),
                HttpMethod.DELETE, request, User.class);
    }
  
    publicstatic void main(String args[]){
        AuthTokenInfo tokenInfo = sendTokenRequest();
        listAllUsers(tokenInfo);
         
        getUser(tokenInfo);
         
        createUser(tokenInfo);
        listAllUsers(tokenInfo);
         
        updateUser(tokenInfo);
        listAllUsers(tokenInfo);
         
        deleteUser(tokenInfo);
        listAllUsers(tokenInfo);
         
        deleteAllUsers(tokenInfo);
        listAllUsers(tokenInfo);
    }
}

Above code will produce following output:

AuthTokenInfo [access_token=fceed386-5923-4bf8-b193-1d76f95da4c4, token_type=bearer, refresh_token=29d28ee2-9d09-483f-a2d6-7f93e7a31667, expires_in=71, scope=read write trust]
 
Testing listAllUsers API-----------
User : id=1, Name=Sam, Age=30, Salary=70000.0
User : id=2, Name=Tom, Age=40, Salary=50000.0
User : id=3, Name=Jerome, Age=45, Salary=30000.0
User : id=4, Name=Silvia, Age=50, Salary=40000.0
 
Testing getUser API----------
User [id=1, name=Sam, age=30, salary=70000.0]
 
Testing create User API----------
Location : http://localhost:8080/SpringSecurityOAuth2Example/user/5
 
Testing listAllUsers API-----------
User : id=1, Name=Sam, Age=30, Salary=70000.0
User : id=2, Name=Tom, Age=40, Salary=50000.0
User : id=3, Name=Jerome, Age=45, Salary=30000.0
User : id=4, Name=Silvia, Age=50, Salary=40000.0
User : id=5, Name=Sarah, Age=51, Salary=134.0
 
Testing update User API----------
User [id=1, name=Tomy, age=33, salary=70000.0]
 
Testing listAllUsers API-----------
User : id=1, Name=Tomy, Age=33, Salary=70000.0
User : id=2, Name=Tom, Age=40, Salary=50000.0
User : id=3, Name=Jerome, Age=45, Salary=30000.0
User : id=4, Name=Silvia, Age=50, Salary=40000.0
User : id=5, Name=Sarah, Age=51, Salary=134.0
 
Testing delete User API----------
 
Testing listAllUsers API-----------
User : id=1, Name=Tomy, Age=33, Salary=70000.0
User : id=2, Name=Tom, Age=40, Salary=50000.0
User : id=4, Name=Silvia, Age=50, Salary=40000.0
User : id=5, Name=Sarah, Age=51, Salary=134.0
 
Testing all delete Users API----------
 
Testing listAllUsers API-----------
No user exist----------

Project Structure

SpringOAuth2_img10

pom.xml

<projectxmlns="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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.websystique.springmvc</groupId>
    <artifactId>SpringSecurityOAuth2Example</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>
 
    <name>SpringSecurityOAuth2Example</name>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <springframework.version>4.3.1.RELEASE</springframework.version>
        <springsecurity.version>4.1.1.RELEASE</springsecurity.version>
        <springsecurityoauth2.version>2.0.10.RELEASE</springsecurityoauth2.version>
        <jackson.library>2.7.5</jackson.library>
    </properties>
 
    <dependencies>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springframework.version}</version>
        </dependency>
 
        <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${springsecurity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${springsecurity.version}</version>
        </dependency>
 
        <!-- Spring Security OAuth2-->
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>${springsecurityoauth2.version}</version>
        </dependency>
 
        <!-- Jackson libraries -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.library}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>${jackson.library}</version>
        </dependency>
 
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>
 
    <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.7</source>
                        <target>1.7</target>
                    </configuration>
                </plugin>        
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.4</version>
                    <configuration>
                        <warSourceDirectory>src/main/webapp</warSourceDirectory>
                        <warName>SpringSecurityOAuth2Example</warName>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
                </plugin>
            </plugins>
        <finalName>SpringSecurityOAuth2Example</finalName>
    </build>
</project>

Download Source Code



References

  • OAuth2 Specification
  • Spring OAuth2 Official reference
  • Spring Security 4 Project Page
  • Spring Security 4 Reference Manual
websystiqueadmin
If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus &Twitter as well? I would love to hear your thoughts on these articles, it will help me improve further our learning process.

If you appreciate the effort I have put in this learning site, help me improve the visibility of this site towards global audience by sharing and linking this site from within and beyond your network. You & your friends can always link my site from your site on www.websystique.com, and share the learning.

After all, we are here to learn together, aren’t we?


0 0
原创粉丝点击