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 + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/unity/dashboard.jsp b/src/main/webapp/WEB-INF/jsp/unity/dashboard.jsp index 551bbd6..bf1d844 100644 --- a/src/main/webapp/WEB-INF/jsp/unity/dashboard.jsp +++ b/src/main/webapp/WEB-INF/jsp/unity/dashboard.jsp @@ -13,5 +13,10 @@ Home

Hi Unity.

+ +Principal: ${SPRING_SECURITY_CONTEXT.authentication.principal} +
+Logout + \ No newline at end of file diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp index a3ac1a7..059fc5e 100644 --- a/src/main/webapp/index.jsp +++ b/src/main/webapp/index.jsp @@ -4,15 +4,20 @@ --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> Home + +

Spring Security&Oauth2 is work!

+ Login +  |  Logout

@@ -21,7 +26,7 @@
  1. - 菜单 User 是不需要Oauth 验证即可访问的(即公开的resource) + 菜单 User 是不需要Oauth 验证即可访问的(即公开的resource); 用于管理用户信息(添加,删除等).