diff --git a/apollo-common/pom.xml b/apollo-common/pom.xml index 038880b4fa68366c534dd0dfcb8c05bbaf673c82..c57a03b311ab0c494bc19def8a3fb0361bcf4616 100644 --- a/apollo-common/pom.xml +++ b/apollo-common/pom.xml @@ -24,11 +24,11 @@ org.springframework.boot - spring-boot-starter-security + spring-boot-starter-actuator org.springframework.boot - spring-boot-starter-actuator + spring-boot-starter-security org.springframework.cloud diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/controller/WebSecurityConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/auth/WebSecurityConfig.java similarity index 94% rename from apollo-common/src/main/java/com/ctrip/framework/apollo/common/controller/WebSecurityConfig.java rename to apollo-common/src/main/java/com/ctrip/framework/apollo/common/auth/WebSecurityConfig.java index 3b635380d9311c7643a0a4a0d5f1cdba2d0f3c40..b85120e295e13ca32d27b94b21078e7fab12f43b 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/controller/WebSecurityConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/auth/WebSecurityConfig.java @@ -1,4 +1,4 @@ -package com.ctrip.framework.apollo.common.controller; +package com.ctrip.framework.apollo.common.auth; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; diff --git a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/ConfigServiceTestConfiguration.java b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/ConfigServiceTestConfiguration.java index 83728aa08c8c1b0729a1c040799a66293d63801a..ad81b9f621def4fb34f099ac0b0254b9de7f994e 100644 --- a/apollo-configservice/src/test/java/com/ctrip/framework/apollo/ConfigServiceTestConfiguration.java +++ b/apollo-configservice/src/test/java/com/ctrip/framework/apollo/ConfigServiceTestConfiguration.java @@ -1,6 +1,6 @@ package com.ctrip.framework.apollo; -import com.ctrip.framework.apollo.common.controller.WebSecurityConfig; +import com.ctrip.framework.apollo.common.auth.WebSecurityConfig; import com.ctrip.framework.apollo.configservice.ConfigServiceApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; diff --git a/apollo-portal/pom.xml b/apollo-portal/pom.xml index 400b5404653f78bfc358d4346c03a06cc7e69462..1408a3852ee48255acf270fcdce504bf55c815d6 100644 --- a/apollo-portal/pom.xml +++ b/apollo-portal/pom.xml @@ -58,4 +58,18 @@ + + + ctrip + + ctrip + + + + org.jasig.cas.client + cas-client-core-infosec-credis + + + + diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/auth/CtripUserInfoHolder.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/auth/CtripUserInfoHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..19989dcd99c8661dd4123b3f4de52caf0341f03e --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/auth/CtripUserInfoHolder.java @@ -0,0 +1,47 @@ +package com.ctrip.framework.apollo.portal.auth; + +import com.ctrip.framework.apollo.portal.entity.po.UserInfo; + +import java.lang.reflect.Method; + +/** + * ctrip内部实现的获取用户信息 + */ +public class CtripUserInfoHolder implements UserInfoHolder{ + + private Object assertionHolder; + + private Method getAssertion; + + + public CtripUserInfoHolder() { + Class clazz = null; + try { + clazz = Class.forName("org.jasig.cas.client.util.AssertionHolder"); + assertionHolder = clazz.newInstance(); + getAssertion = assertionHolder.getClass().getMethod("getAssertion"); + } catch (Exception e) { + throw new RuntimeException("instance listener fail", e); + } + } + + @Override + public UserInfo getUser() { + try { + + Object assertion = getAssertion.invoke(assertionHolder); + Method getPrincipal = assertion.getClass().getMethod("getPrincipal"); + Object principal = getPrincipal.invoke(assertion); + Method getName = principal.getClass().getMethod("getName"); + String name = (String) getName.invoke(principal); + + UserInfo userInfo = new UserInfo(); + userInfo.setUsername(name); + + return userInfo; + } catch (Exception e) { + throw new RuntimeException("", e); + } + } + +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/auth/NotCtripUserInfoHolder.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/auth/NotCtripUserInfoHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..09c7e325d4750885cfff8e1baac7217447a40fd9 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/auth/NotCtripUserInfoHolder.java @@ -0,0 +1,21 @@ +package com.ctrip.framework.apollo.portal.auth; + +import com.ctrip.framework.apollo.portal.entity.po.UserInfo; + +/** + * 不是ctrip的公司默认提供一个假用户 + */ +public class NotCtripUserInfoHolder implements UserInfoHolder{ + + + public NotCtripUserInfoHolder(){ + + } + + @Override + public UserInfo getUser() { + UserInfo userInfo = new UserInfo(); + userInfo.setUsername("apollo"); + return userInfo; + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/auth/UserInfoHolder.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/auth/UserInfoHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..38ae33e044cc48e812b9fe495a48a1316d93f1f5 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/auth/UserInfoHolder.java @@ -0,0 +1,12 @@ +package com.ctrip.framework.apollo.portal.auth; + +import com.ctrip.framework.apollo.portal.entity.po.UserInfo; + +/** + * 获取登录用户的信息,不同的公司应该有不同的实现 + */ +public interface UserInfoHolder { + + UserInfo getUser(); + +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/AuthConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/AuthConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..a5ba62316f0a597a04074b9e90d35cd993ee87c7 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/AuthConfiguration.java @@ -0,0 +1,149 @@ +package com.ctrip.framework.apollo.portal.configutation; + +import com.ctrip.framework.apollo.portal.auth.CtripUserInfoHolder; +import com.ctrip.framework.apollo.portal.auth.NotCtripUserInfoHolder; +import com.ctrip.framework.apollo.portal.repository.ServerConfigRepository; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.FilterRegistrationBean; +import org.springframework.boot.context.embedded.ServletListenerRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import java.util.EventListener; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.Filter; + + +/** + * sso相关的配置. + */ +@Configuration +public class AuthConfiguration { + + + /** + * 在ctrip内部运行时,会指定 spring.profiles.active = ctrip. + * ctrip sso是通过cas实现的,所以需要加载相关的filter和listener. + */ + @Configuration + @Profile("ctrip") + static class CtripProfileConfiguration{ + + @Autowired + private ServerConfigRepository serverConfigRepository; + + @Bean + public ServletListenerRegistrationBean redisAppSettingListner(){ + ServletListenerRegistrationBean redisAppSettingListner = new ServletListenerRegistrationBean(); + redisAppSettingListner.setListener(listener("org.jasig.cas.client.credis.CRedisAppSettingListner")); + return redisAppSettingListner; + } + + @Bean + public ServletListenerRegistrationBean singleSignOutHttpSessionListener(){ + ServletListenerRegistrationBean singleSignOutHttpSessionListener = new ServletListenerRegistrationBean(); + singleSignOutHttpSessionListener.setListener(listener("org.jasig.cas.client.session.SingleSignOutHttpSessionListener")); + return singleSignOutHttpSessionListener; + } + + @Bean + public FilterRegistrationBean casFilter(){ + FilterRegistrationBean singleSignOutFilter = new FilterRegistrationBean(); + singleSignOutFilter.setFilter(filter("org.jasig.cas.client.session.SingleSignOutFilter")); + singleSignOutFilter.addUrlPatterns("/*"); + return singleSignOutFilter; + } + + @Bean + public FilterRegistrationBean authenticationFilter(){ + FilterRegistrationBean casFilter = new FilterRegistrationBean(); + + Map filterInitParam = new HashMap(); + filterInitParam.put("redisClusterName", "casClientPrincipal"); + filterInitParam.put("serverName", serverConfigRepository.findByKey("serverName").getValue()); + filterInitParam.put("casServerLoginUrl", serverConfigRepository.findByKey("casServerLoginUrl").getValue()); + + casFilter.setInitParameters(filterInitParam); + casFilter.setFilter(filter("org.jasig.cas.client.authentication.AuthenticationFilter")); + casFilter.addUrlPatterns("/*"); + + return casFilter; + } + + @Bean + public FilterRegistrationBean casValidationFilter(){ + FilterRegistrationBean casValidationFilter = new FilterRegistrationBean(); + Map filterInitParam = new HashMap(); + filterInitParam.put("casServerUrlPrefix", serverConfigRepository.findByKey("casServerUrlPrefix").getValue()); + filterInitParam.put("serverName", serverConfigRepository.findByKey("serverName").getValue()); + filterInitParam.put("encoding", "UTF-8"); + filterInitParam.put("useRedis", "true"); + filterInitParam.put("redisClusterName", "casClientPrincipal"); + + casValidationFilter.setFilter(filter("org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter")); + casValidationFilter.setInitParameters(filterInitParam); + casValidationFilter.addUrlPatterns("/*"); + + return casValidationFilter; + + } + + + + @Bean + public FilterRegistrationBean assertionHolder(){ + FilterRegistrationBean assertionHolderFilter = new FilterRegistrationBean(); + + assertionHolderFilter.setFilter(filter("org.jasig.cas.client.util.AssertionThreadLocalFilter")); + assertionHolderFilter.addUrlPatterns("/*"); + + return assertionHolderFilter; + } + + @Bean + public CtripUserInfoHolder ctripUserInfoHolder(){ + return new CtripUserInfoHolder(); + } + + private Filter filter(String className){ + Class clazz = null; + try { + clazz = Class.forName(className); + Object obj = clazz.newInstance(); + return (Filter) obj; + } catch (Exception e) { + throw new RuntimeException("instance filter fail", e); + } + + } + + private EventListener listener(String className){ + Class clazz = null; + try { + clazz = Class.forName(className); + Object obj = clazz.newInstance(); + return (EventListener) obj; + } catch (Exception e) { + throw new RuntimeException("instance listener fail", e); + } + } + } + + /** + * 默认实现 + */ + @Configuration + static class NotCtripProfileConfiguration{ + + @Bean + public NotCtripUserInfoHolder notCtripUserInfoHolder(){ + return new NotCtripUserInfoHolder(); + } + } + + +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/ServletContextConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/ServletContextConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..0c4ae3e3af2a14b3253a21e14c4e47e15a34be88 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/configutation/ServletContextConfiguration.java @@ -0,0 +1,37 @@ +package com.ctrip.framework.apollo.portal.configutation; + +import com.ctrip.framework.apollo.portal.entity.po.ServerConfig; +import com.ctrip.framework.apollo.portal.repository.ServerConfigRepository; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.ServletContextInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +@Configuration +public class ServletContextConfiguration { + + @Autowired + private ServerConfigRepository serverConfigRepository; + + @Bean + public ServletContextInitializer initializer(){ + + return new ServletContextInitializer() { + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + ServerConfig loggingServerIP = serverConfigRepository.findByKey("loggingServerIP"); + ServerConfig loggingServerPort = serverConfigRepository.findByKey("loggingServerPort"); + ServerConfig credisServiceUrl = serverConfigRepository.findByKey("credisServiceUrl"); + servletContext.setInitParameter("loggingServerIP", loggingServerIP == null? "":loggingServerIP.getValue()); + servletContext.setInitParameter("loggingServerPort", loggingServerPort == null? "":loggingServerPort.getValue()); + servletContext.setInitParameter("credisServiceUrl", credisServiceUrl == null? "":credisServiceUrl.getValue()); + } + }; + } + +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PortalAppController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PortalAppController.java index 782f79de66021471103816e150620de0e5259422..183adcf7dc08e828864cdee9fb688042d35d5026 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PortalAppController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PortalAppController.java @@ -34,6 +34,7 @@ public class PortalAppController { @RequestMapping("/envs/{env}") public List findAllApp(@PathVariable String env){ + if (StringUtils.isEmpty(env)){ throw new BadRequestException("env can not be empty"); } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PortalUserInfoController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PortalUserInfoController.java new file mode 100644 index 0000000000000000000000000000000000000000..47d8ddf6e65efb66046fb7a58dcb6eea3cd3ba56 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/PortalUserInfoController.java @@ -0,0 +1,72 @@ +package com.ctrip.framework.apollo.portal.controller; + +import com.ctrip.framework.apollo.core.exception.BadRequestException; +import com.ctrip.framework.apollo.portal.auth.CtripUserInfoHolder; +import com.ctrip.framework.apollo.portal.auth.NotCtripUserInfoHolder; +import com.ctrip.framework.apollo.portal.auth.UserInfoHolder; +import com.ctrip.framework.apollo.portal.entity.po.UserInfo; +import com.ctrip.framework.apollo.portal.repository.ServerConfigRepository; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; + +import javax.annotation.PostConstruct; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@RestController +public class PortalUserInfoController { + private static Logger logger = LoggerFactory.getLogger(PortalUserInfoController.class); + + @Autowired + private ApplicationContext applicationContext; + @Autowired + private ServerConfigRepository serverConfigRepository; + + private UserInfoHolder userInfoHolder; + + @PostConstruct + public void post() { + try { + userInfoHolder = applicationContext.getBean(CtripUserInfoHolder.class); + } catch (NoSuchBeanDefinitionException e) { + logger.debug("default user info holder"); + userInfoHolder = applicationContext.getBean(NotCtripUserInfoHolder.class); + } + } + + @RequestMapping("/user") + public UserInfo getCurrentUserName() { + try { + return userInfoHolder.getUser(); + } catch (Exception e) { + throw new BadRequestException("请先登录"); + } + } + + @RequestMapping("/user/logout") + public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException { + //将session销毁 + request.getSession().invalidate(); + + Cookie cookie = new Cookie("memCacheAssertionID", null); + //将cookie的有效期设置为0,命令浏览器删除该cookie + cookie.setMaxAge(0); + cookie.setPath(request.getContextPath() + "/"); + response.addCookie(cookie); + + //重定向到SSO的logout地址 + String casServerUrl = serverConfigRepository.findByKey("casServerUrlPrefix").getValue(); + String serverName = serverConfigRepository.findByKey("casServerUrlPrefix").getValue(); + + response.sendRedirect(casServerUrl + "/logout?service=" + serverName); + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserInfo.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..ded061db819d56ce3fec41ebcbe52380ecfff1ca --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/po/UserInfo.java @@ -0,0 +1,13 @@ +package com.ctrip.framework.apollo.portal.entity.po; + +public class UserInfo { + private String username; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/apollo-portal/src/main/resources/portal.properties b/apollo-portal/src/main/resources/portal.properties index 37ae35c18f6093837275b7a233a080e4f5fba469..454f44d9bdcec6205dc134433715ffe8893755a7 100644 --- a/apollo-portal/src/main/resources/portal.properties +++ b/apollo-portal/src/main/resources/portal.properties @@ -3,3 +3,5 @@ apollo.portal.envs= fat,uat,pro ctrip.appid= 100003173 server.port= 8070 logging.file= /opt/logs/100003173/apollo-portal.log + +server.context_parameters.appid = ${ctrip.appid} diff --git a/apollo-portal/src/main/resources/static/app.html b/apollo-portal/src/main/resources/static/app.html index c805d520e43bf512da6eafa23f1467a4c0d70d8d..e4fe5b8ff16a62b23f2939d82612406b06a0362e 100644 --- a/apollo-portal/src/main/resources/static/app.html +++ b/apollo-portal/src/main/resources/static/app.html @@ -81,6 +81,7 @@ + diff --git a/apollo-portal/src/main/resources/static/config.html b/apollo-portal/src/main/resources/static/config.html index 1320dfbe666b0a5a749026a75a62df11ea301a8a..ba50f22dcd0e07f8a26ebcd397f86cd00a15eccb 100644 --- a/apollo-portal/src/main/resources/static/config.html +++ b/apollo-portal/src/main/resources/static/config.html @@ -609,6 +609,7 @@ + diff --git a/apollo-portal/src/main/resources/static/config/sync.html b/apollo-portal/src/main/resources/static/config/sync.html index 93acc0af039270ca9fe150bb37453c7cb5709f14..4f200b5a782b8096f857cc28b85990e9997f5b3f 100644 --- a/apollo-portal/src/main/resources/static/config/sync.html +++ b/apollo-portal/src/main/resources/static/config/sync.html @@ -190,6 +190,7 @@ + diff --git a/apollo-portal/src/main/resources/static/namespace.html b/apollo-portal/src/main/resources/static/namespace.html index cbffa36d5a42320c2f9a285bba7e9a4ea0faef6f..9ba8886188262a3172aadf98f8a660fc68b54d9e 100644 --- a/apollo-portal/src/main/resources/static/namespace.html +++ b/apollo-portal/src/main/resources/static/namespace.html @@ -105,6 +105,7 @@ + diff --git a/apollo-portal/src/main/resources/static/scripts/directive.js b/apollo-portal/src/main/resources/static/scripts/directive.js index 1128a9788cb0d8731225d8168e361bce79a54060..1489f28382891529279467c7a9c576642c31f657 100644 --- a/apollo-portal/src/main/resources/static/scripts/directive.js +++ b/apollo-portal/src/main/resources/static/scripts/directive.js @@ -1,5 +1,5 @@ /** navbar */ -directive_module.directive('apollonav', function ($compile, $window, toastr, AppUtil, AppService, EnvService) { +directive_module.directive('apollonav', function ($compile, $window, toastr, AppUtil, AppService, EnvService, UserService) { return { restrict: 'E', templateUrl: '../views/common/nav.html', @@ -110,6 +110,12 @@ directive_module.directive('apollonav', function ($compile, $window, toastr, App selectedAppIdx = -1; } + + UserService.load_user().then(function (result) { + scope.userName = result.username; + }, function (result) { + + }); } } diff --git a/apollo-portal/src/main/resources/static/scripts/services/UserService.js b/apollo-portal/src/main/resources/static/scripts/services/UserService.js new file mode 100644 index 0000000000000000000000000000000000000000..0f7a76eedddf125f82aaf346005e07758f1f736c --- /dev/null +++ b/apollo-portal/src/main/resources/static/scripts/services/UserService.js @@ -0,0 +1,21 @@ +appService.service('UserService', ['$resource', '$q', function ($resource, $q) { + var user_resource = $resource('', {}, { + load_user:{ + method: 'GET', + url:'/user' + } + }); + return { + load_user: function () { + var d = $q.defer(); + user_resource.load_user({ + }, + function (result) { + d.resolve(result); + }, function (result) { + d.reject(result); + }); + return d.promise; + } + } +}]); diff --git a/apollo-portal/src/main/resources/static/views/common/nav.html b/apollo-portal/src/main/resources/static/views/common/nav.html index bc34bdf1583e13c484cbb5e5fce50745bad6ab9b..509a7ce2cb668dc79102b7d723c6391ef0117ecb 100644 --- a/apollo-portal/src/main/resources/static/views/common/nav.html +++ b/apollo-portal/src/main/resources/static/views/common/nav.html @@ -12,9 +12,9 @@ diff --git a/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/AbstractPortalTest.java b/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/AbstractPortalTest.java index 98bcac441b4832061e0ced38bee226f3f9b2fc02..695fd00fa7f776becfd79f779e11a373b7ce6337 100644 --- a/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/AbstractPortalTest.java +++ b/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/AbstractPortalTest.java @@ -1,5 +1,6 @@ package com.ctrip.framework.apollo.portal; + import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.SpringApplicationConfiguration; @@ -25,4 +26,5 @@ public abstract class AbstractPortalTest { @Value("${local.server.port}") int port; + } diff --git a/pom.xml b/pom.xml index 9ebadb1ade4cdf78781d13979e3d0ce0a89165c8..6f5b83fd3605ab50c865336dd74261943d5075f6 100644 --- a/pom.xml +++ b/pom.xml @@ -176,6 +176,11 @@ + + org.jasig.cas.client + cas-client-core-infosec-credis + 3.1.12 + mysql