diff --git a/others/oauth_test.txt b/others/oauth_test.txt
index 2f3b7cb..20fd0f1 100644
--- a/others/oauth_test.txt
+++ b/others/oauth_test.txt
@@ -37,6 +37,24 @@ http://localhost:8080/spring-oauth-server/unity/dashboard.htm?access_token=3420d
http://localhost:8080/spring-oauth-server/oauth/token?client_id=mobile-client&client_secret=mobile&grant_type=refresh_token&refresh_token=b36f4978-a172-4aa8-af89-60f58abe3ba1
+Restful OAuth2 Test [POST]
+URL: /oauth2/rest_token
+ContentType: application/json
+
+DEMO URL: http://localhost:8080/spring-oauth-server/oauth2/rest_token
+Request Body: {"grant_type":"client_credentials","scope":"read","client_id":"credentials","client_secret":"credentials","username":"user","password":"123"}
+
+Response Body:
+{
+ "access_token": "cd165ebc-562d-45df-8488-9f1ba947553e",
+ "token_type": "bearer",
+ "expires_in": 43193,
+ "scope": "read"
+}
+
+
+
+
更多的测试请访问
http://git.oschina.net/mkk/spring-oauth-client
diff --git a/src/main/java/com/monkeyk/sos/web/controller/OAuthRestController.java b/src/main/java/com/monkeyk/sos/web/controller/OAuthRestController.java
new file mode 100644
index 0000000..1a3dae0
--- /dev/null
+++ b/src/main/java/com/monkeyk/sos/web/controller/OAuthRestController.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
+ * www.monkeyk.com
+ * All rights reserved.
+ *
+ * This software is the confidential and proprietary information of
+ * MONKEYK Information Technology Co. Ltd ("Confidential Information").
+ * You shall not disclose such Confidential Information and shall use
+ * it only in accordance with the terms of the license agreement you
+ * entered into with MONKEYK Information Technology Co. Ltd.
+ */
+package com.monkeyk.sos.web.controller;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.common.exceptions.*;
+import org.springframework.security.oauth2.common.util.OAuth2Utils;
+import org.springframework.security.oauth2.provider.*;
+import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter;
+import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
+import org.springframework.security.oauth2.provider.code.AuthorizationCodeTokenGranter;
+import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
+import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
+import org.springframework.security.oauth2.provider.implicit.ImplicitTokenGranter;
+import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
+import org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter;
+import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
+import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.stereotype.Controller;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * 2016/3/8
+ *
+ * Restful OAuth API
+ *
+ * @author Shengzhao Li
+ * @see org.springframework.security.oauth2.provider.endpoint.TokenEndpoint
+ */
+@Controller
+public class OAuthRestController implements InitializingBean, ApplicationContextAware {
+
+
+ private static final Logger LOG = LoggerFactory.getLogger(OAuthRestController.class);
+
+ @Autowired
+ private ClientDetailsService clientDetailsService;
+ @Autowired
+ private AuthorizationServerTokenServices tokenServices;
+ @Autowired
+ private AuthorizationCodeServices authorizationCodeServices;
+
+ private AuthenticationManager authenticationManager;
+
+ private OAuth2RequestFactory oAuth2RequestFactory;
+
+ private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();
+ private WebResponseExceptionTranslator providerExceptionHandler = new DefaultWebResponseExceptionTranslator();
+
+
+ @RequestMapping(value = "/oauth2/rest_token", method = RequestMethod.POST)
+ @ResponseBody
+ public OAuth2AccessToken postAccessToken(@RequestBody Map parameters) {
+
+
+ String clientId = getClientId(parameters);
+ ClientDetails authenticatedClient = clientDetailsService.loadClientByClientId(clientId);
+
+ TokenRequest tokenRequest = oAuth2RequestFactory.createTokenRequest(parameters, authenticatedClient);
+
+ if (clientId != null && !clientId.equals("")) {
+ // Only validate the client details if a client authenticated during this
+ // request.
+ if (!clientId.equals(tokenRequest.getClientId())) {
+ // double check to make sure that the client ID in the token request is the same as that in the
+ // authenticated client
+ throw new InvalidClientException("Given client ID does not match authenticated client");
+ }
+ }
+
+ if (authenticatedClient != null) {
+ oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
+ }
+
+ final String grantType = tokenRequest.getGrantType();
+ if (!StringUtils.hasText(grantType)) {
+ throw new InvalidRequestException("Missing grant type");
+ }
+ if (grantType.equals("implicit")) {
+ throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
+ }
+
+ if (isAuthCodeRequest(parameters)) {
+ // The scope was requested or determined during the authorization step
+ if (!tokenRequest.getScope().isEmpty()) {
+ LOG.debug("Clearing scope of incoming token request");
+ tokenRequest.setScope(Collections.emptySet());
+ }
+ }
+
+
+ if (isRefreshTokenRequest(parameters)) {
+ // A refresh token has its own default scopes, so we should ignore any added by the factory here.
+ tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
+ }
+
+ OAuth2AccessToken token = getTokenGranter(grantType).grant(grantType, tokenRequest);
+ if (token == null) {
+ throw new UnsupportedGrantTypeException("Unsupported grant type: " + grantType);
+ }
+
+
+ return token;
+
+ }
+
+ protected TokenGranter getTokenGranter(String grantType) {
+
+ if ("authorization_code".equals(grantType)) {
+ return new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetailsService, this.oAuth2RequestFactory);
+ } else if ("password".equals(grantType)) {
+ return new ResourceOwnerPasswordTokenGranter(getAuthenticationManager(), tokenServices, clientDetailsService, this.oAuth2RequestFactory);
+ } else if ("refresh_token".equals(grantType)) {
+ return new RefreshTokenGranter(tokenServices, clientDetailsService, this.oAuth2RequestFactory);
+ } else if ("client_credentials".equals(grantType)) {
+ return new ClientCredentialsTokenGranter(tokenServices, clientDetailsService, this.oAuth2RequestFactory);
+ } else if ("implicit".equals(grantType)) {
+ return new ImplicitTokenGranter(tokenServices, clientDetailsService, this.oAuth2RequestFactory);
+ } else {
+ throw new UnsupportedGrantTypeException("Unsupport grant_type: " + grantType);
+ }
+ }
+
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleException(Exception e) throws Exception {
+ LOG.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
+ return getExceptionTranslator().translate(e);
+ }
+
+ @ExceptionHandler(ClientRegistrationException.class)
+ public ResponseEntity handleClientRegistrationException(Exception e) throws Exception {
+ LOG.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
+ return getExceptionTranslator().translate(new BadClientCredentialsException());
+ }
+
+ @ExceptionHandler(OAuth2Exception.class)
+ public ResponseEntity handleException(OAuth2Exception e) throws Exception {
+ LOG.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
+ return getExceptionTranslator().translate(e);
+ }
+
+
+
+ private boolean isRefreshTokenRequest(Map parameters) {
+ return "refresh_token".equals(parameters.get("grant_type")) && parameters.get("refresh_token") != null;
+ }
+
+ private boolean isAuthCodeRequest(Map parameters) {
+ return "authorization_code".equals(parameters.get("grant_type")) && parameters.get("code") != null;
+ }
+
+
+ protected String getClientId(Map parameters) {
+ return parameters.get("client_id");
+ }
+
+ private AuthenticationManager getAuthenticationManager() {
+ return this.authenticationManager;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+
+ Assert.state(clientDetailsService != null, "ClientDetailsService must be provided");
+ Assert.state(authenticationManager != null, "AuthenticationManager must be provided");
+
+ oAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetailsService);
+ }
+
+ protected WebResponseExceptionTranslator getExceptionTranslator() {
+ return providerExceptionHandler;
+ }
+
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ if (this.authenticationManager == null) {
+ this.authenticationManager = (AuthenticationManager) applicationContext.getBean("authenticationManager");
+ }
+ }
+}
diff --git a/src/main/webapp/WEB-INF/jsp/decorators/main.jsp b/src/main/webapp/WEB-INF/jsp/decorators/main.jsp
index eefaf5e..c14a04b 100644
--- a/src/main/webapp/WEB-INF/jsp/decorators/main.jsp
+++ b/src/main/webapp/WEB-INF/jsp/decorators/main.jsp
@@ -29,7 +29,7 @@
- © 2013 - 2015
+ © 2013 - 2016
sz@monkeyk.com from spring-oauth-server
diff --git a/src/main/webapp/WEB-INF/jsp/mobile/dashboard.jsp b/src/main/webapp/WEB-INF/jsp/mobile/dashboard.jsp
index 86af062..7e18ae7 100644
--- a/src/main/webapp/WEB-INF/jsp/mobile/dashboard.jsp
+++ b/src/main/webapp/WEB-INF/jsp/mobile/dashboard.jsp
@@ -13,5 +13,10 @@
Home
Hi Mobile.
+
+Principal:
${SPRING_SECURITY_CONTEXT.authentication.principal}
+
+
Logout
+