├── .gitignore ├── Chapter1 ├── README.md └── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ └── cas │ │ └── config │ │ ├── cas.properties │ │ └── log4j2.xml │ ├── maven │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ └── main │ └── resources │ ├── application.properties │ └── thekeystore ├── Chapter10 ├── README.md ├── cas-management-overlay │ ├── .gitignore │ ├── LICENSE.txt │ ├── README.md │ ├── build.cmd │ ├── build.sh │ ├── etc │ │ └── cas │ │ │ └── config │ │ │ ├── log4j2-management.xml │ │ │ ├── management.properties │ │ │ └── users.properties │ ├── maven │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ │ └── main │ │ └── resources │ │ ├── application.properties │ │ ├── thekeystore │ │ └── user-details.properties ├── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ │ └── cas │ │ │ └── config │ │ │ ├── cas.properties │ │ │ └── log4j2.xml │ ├── maven │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── net │ │ │ └── anumbrella │ │ │ └── sso │ │ │ ├── action │ │ │ └── ValidateLoginAction.java │ │ │ ├── authentication │ │ │ ├── CustomUsernamePasswordAuthentication.java │ │ │ └── CustomerHandlerAuthentication.java │ │ │ ├── config │ │ │ ├── CustomAuthenticationConfiguration.java │ │ │ ├── CustomControllerConfigurer.java │ │ │ ├── CustomWebflowConfigurer.java │ │ │ └── CustomerAuthWebflowConfiguration.java │ │ │ ├── controller │ │ │ ├── CaptchaController.java │ │ │ └── ServicesManagerController.java │ │ │ ├── entity │ │ │ ├── CustomCredential.java │ │ │ └── User.java │ │ │ ├── exection │ │ │ └── CheckCodeErrorException.java │ │ │ └── utils │ │ │ ├── CaptchaCodeUtils.java │ │ │ └── KaptchaCodeUtils.java │ │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── anumbrella.properties │ │ ├── application.properties │ │ ├── messages_zh_CN.properties │ │ ├── services │ │ ├── web-10000001.json │ │ └── web-10000001.yml │ │ ├── shiro.ini │ │ ├── static │ │ └── themes │ │ │ └── anumbrella │ │ │ ├── css │ │ │ └── cas.css │ │ │ ├── images │ │ │ └── po.jpeg │ │ │ └── js │ │ │ ├── cas.js │ │ │ └── code.js │ │ ├── templates │ │ └── anumbrella │ │ │ └── casLoginView.html │ │ └── thekeystore └── client-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── net │ │ └── anumbrella │ │ └── sso │ │ ├── Application.java │ │ ├── config │ │ ├── CasCustomConfig.java │ │ ├── SpringCasAutoconfig.java │ │ └── WebSecurityConfig.java │ │ ├── controller │ │ └── IndexController.java │ │ ├── dao │ │ └── LoginDao.java │ │ ├── entity │ │ └── User.java │ │ └── service │ │ └── LoginService.java │ └── resources │ ├── application.properties │ └── templates │ ├── index.html │ └── login.html ├── Chapter11 ├── README.md └── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ └── cas │ │ └── config │ │ ├── cas.properties │ │ └── log4j2.xml │ ├── maven │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── net │ │ └── anumbrella │ │ └── sso │ │ ├── action │ │ └── ValidateLoginAction.java │ │ ├── authentication │ │ ├── CustomUsernamePasswordAuthentication.java │ │ └── CustomerHandlerAuthentication.java │ │ ├── config │ │ ├── CustomAuthenticationConfiguration.java │ │ ├── CustomControllerConfigurer.java │ │ ├── CustomWebflowConfigurer.java │ │ └── CustomerAuthWebflowConfiguration.java │ │ ├── controller │ │ ├── CaptchaController.java │ │ └── ServicesManagerController.java │ │ ├── entity │ │ ├── CustomCredential.java │ │ └── User.java │ │ ├── exection │ │ └── CheckCodeErrorException.java │ │ └── utils │ │ ├── CaptchaCodeUtils.java │ │ └── KaptchaCodeUtils.java │ └── resources │ ├── META-INF │ └── spring.factories │ ├── anumbrella.properties │ ├── application.properties │ ├── messages_zh_CN.properties │ ├── services │ ├── web-10000001.json │ └── web-10000001.yml │ ├── shiro.ini │ ├── static │ └── themes │ │ └── anumbrella │ │ ├── css │ │ └── cas.css │ │ ├── images │ │ └── po.jpeg │ │ └── js │ │ ├── cas.js │ │ └── code.js │ ├── templates │ └── anumbrella │ │ └── casLoginView.html │ └── thekeystore ├── Chapter12 ├── README.md ├── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ │ └── cas │ │ │ └── config │ │ │ ├── cas.properties │ │ │ └── log4j2.xml │ ├── maven │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── net │ │ │ └── anumbrella │ │ │ └── sso │ │ │ ├── action │ │ │ └── ValidateLoginAction.java │ │ │ ├── authentication │ │ │ ├── CustomUsernamePasswordAuthentication.java │ │ │ └── CustomerHandlerAuthentication.java │ │ │ ├── config │ │ │ ├── CustomAuthenticationConfiguration.java │ │ │ ├── CustomControllerConfigurer.java │ │ │ ├── CustomWebflowConfigurer.java │ │ │ └── CustomerAuthWebflowConfiguration.java │ │ │ ├── controller │ │ │ ├── CaptchaController.java │ │ │ └── ServicesManagerController.java │ │ │ ├── entity │ │ │ ├── CustomCredential.java │ │ │ └── User.java │ │ │ ├── exection │ │ │ └── CheckCodeErrorException.java │ │ │ └── utils │ │ │ ├── CaptchaCodeUtils.java │ │ │ └── KaptchaCodeUtils.java │ │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── anumbrella.properties │ │ ├── application.properties │ │ ├── messages_zh_CN.properties │ │ ├── services │ │ ├── web-10000001.json │ │ └── web-10000001.yml │ │ ├── shiro.ini │ │ ├── static │ │ └── themes │ │ │ └── anumbrella │ │ │ ├── css │ │ │ └── cas.css │ │ │ ├── images │ │ │ └── po.jpeg │ │ │ └── js │ │ │ ├── cas.js │ │ │ └── code.js │ │ ├── templates │ │ └── anumbrella │ │ │ └── casLoginView.html │ │ └── thekeystore ├── client-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── net │ │ │ └── anumbrella │ │ │ └── sso │ │ │ ├── Application.java │ │ │ ├── config │ │ │ ├── CasCustomConfig.java │ │ │ ├── SpringCasAutoconfig.java │ │ │ └── WebSecurityConfig.java │ │ │ ├── controller │ │ │ └── IndexController.java │ │ │ ├── dao │ │ │ └── UserDao.java │ │ │ ├── entity │ │ │ ├── ResponseResult.java │ │ │ └── User.java │ │ │ └── service │ │ │ └── UserService.java │ │ └── resources │ │ └── application.properties └── front-demo │ ├── .gitignore │ ├── CODE_OF_CONDUCT.md │ ├── Dockerfile │ ├── Dockerfile.dev │ ├── Dockerfile.hub │ ├── LICENSE │ ├── README.md │ ├── README.ru-RU.md │ ├── README.zh-CN.md │ ├── appveyor.yml │ ├── config │ ├── config.js │ ├── plugin.config.js │ └── router.config.js │ ├── docker │ ├── docker-compose.dev.yml │ ├── docker-compose.yml │ └── nginx.conf │ ├── firebase.json │ ├── jest-puppeteer.config.js │ ├── jest.config.js │ ├── jsconfig.json │ ├── mock │ ├── api.js │ ├── chart.js │ ├── geographic.js │ ├── geographic │ │ ├── city.json │ │ └── province.json │ ├── notices.js │ ├── profile.js │ ├── route.js │ ├── rule.js │ └── user.js │ ├── netlify.toml │ ├── package.json │ ├── public │ ├── favicon.png │ └── icons │ │ ├── icon-128x128.png │ │ ├── icon-192x192.png │ │ └── icon-512x512.png │ ├── scripts │ ├── generateMock.js │ ├── getPrettierFiles.js │ ├── lint-prettier.js │ └── prettier.js │ ├── src │ ├── app.js │ ├── assets │ │ └── logo.svg │ ├── components │ │ ├── Authorized │ │ │ ├── Authorized.js │ │ │ ├── AuthorizedRoute.d.ts │ │ │ ├── AuthorizedRoute.js │ │ │ ├── CheckPermissions.js │ │ │ ├── CheckPermissions.test.js │ │ │ ├── PromiseRender.js │ │ │ ├── Secured.js │ │ │ ├── demo │ │ │ │ ├── AuthorizedArray.md │ │ │ │ ├── AuthorizedFunction.md │ │ │ │ ├── basic.md │ │ │ │ └── secured.md │ │ │ ├── index.d.ts │ │ │ ├── index.js │ │ │ ├── index.md │ │ │ └── renderAuthorize.js │ │ ├── Exception │ │ │ ├── demo │ │ │ │ ├── 403.md │ │ │ │ ├── 404.md │ │ │ │ └── 500.md │ │ │ ├── index.d.ts │ │ │ ├── index.en-US.md │ │ │ ├── index.js │ │ │ ├── index.less │ │ │ ├── index.zh-CN.md │ │ │ └── typeConfig.js │ │ ├── Login │ │ │ ├── LoginItem.d.ts │ │ │ ├── LoginItem.js │ │ │ ├── LoginSubmit.js │ │ │ ├── LoginTab.d.ts │ │ │ ├── LoginTab.js │ │ │ ├── demo │ │ │ │ └── basic.md │ │ │ ├── index.d.ts │ │ │ ├── index.en-US.md │ │ │ ├── index.js │ │ │ ├── index.less │ │ │ ├── index.zh-CN.md │ │ │ ├── loginContext.js │ │ │ └── map.js │ │ ├── PageHeader │ │ │ ├── breadcrumb.d.ts │ │ │ ├── breadcrumb.js │ │ │ ├── demo │ │ │ │ ├── image.md │ │ │ │ ├── simple.md │ │ │ │ ├── standard.md │ │ │ │ └── structure.md │ │ │ ├── index.d.ts │ │ │ ├── index.js │ │ │ ├── index.less │ │ │ ├── index.md │ │ │ └── index.test.js │ │ ├── PageHeaderWrapper │ │ │ ├── GridContent.js │ │ │ ├── GridContent.less │ │ │ ├── index.js │ │ │ └── index.less │ │ ├── PageLoading │ │ │ └── index.js │ │ ├── StandardTable │ │ │ ├── index.js │ │ │ └── index.less │ │ └── _utils │ │ │ ├── pathTools.js │ │ │ └── pathTools.test.js │ ├── defaultSettings.js │ ├── e2e │ │ ├── baseLayout.e2e.js │ │ ├── home.e2e.js │ │ ├── login.e2e.js │ │ ├── topMenu.e2e.js │ │ └── userLayout.e2e.js │ ├── global.js │ ├── global.less │ ├── layouts │ │ ├── MenuContext.js │ │ ├── UserLayout.js │ │ └── UserLayout.less │ ├── locales │ │ ├── en-US.js │ │ ├── en-US │ │ │ ├── analysis.js │ │ │ ├── exception.js │ │ │ ├── form.js │ │ │ ├── globalHeader.js │ │ │ ├── login.js │ │ │ ├── menu.js │ │ │ ├── monitor.js │ │ │ ├── pwa.js │ │ │ ├── result.js │ │ │ ├── settingDrawer.js │ │ │ └── settings.js │ │ ├── pt-BR.js │ │ ├── pt-BR │ │ │ ├── analysis.js │ │ │ ├── exception.js │ │ │ ├── form.js │ │ │ ├── globalHeader.js │ │ │ ├── login.js │ │ │ ├── menu.js │ │ │ ├── monitor.js │ │ │ ├── pwa.js │ │ │ ├── result.js │ │ │ ├── settingDrawer.js │ │ │ └── settings.js │ │ ├── zh-CN.js │ │ ├── zh-CN │ │ │ ├── analysis.js │ │ │ ├── exception.js │ │ │ ├── form.js │ │ │ ├── globalHeader.js │ │ │ ├── login.js │ │ │ ├── menu.js │ │ │ ├── monitor.js │ │ │ ├── pwa.js │ │ │ ├── result.js │ │ │ ├── settingDrawer.js │ │ │ └── settings.js │ │ ├── zh-TW.js │ │ └── zh-TW │ │ │ ├── analysis.js │ │ │ ├── exception.js │ │ │ ├── form.js │ │ │ ├── globalHeader.js │ │ │ ├── login.js │ │ │ ├── menu.js │ │ │ ├── monitor.js │ │ │ ├── pwa.js │ │ │ ├── result.js │ │ │ ├── settingDrawer.js │ │ │ └── settings.js │ ├── manifest.json │ ├── models │ │ ├── global.js │ │ ├── login.js │ │ ├── setting.js │ │ └── user.js │ ├── pages │ │ ├── Authorized.js │ │ ├── Exception │ │ │ ├── 403.js │ │ │ ├── 404.js │ │ │ ├── 500.js │ │ │ ├── TriggerException.js │ │ │ ├── models │ │ │ │ └── error.js │ │ │ └── style.less │ │ ├── Home │ │ │ ├── Index.js │ │ │ └── Index.less │ │ ├── User │ │ │ ├── Login.js │ │ │ └── Login.less │ │ └── document.ejs │ ├── service-worker.js │ ├── services │ │ ├── api.js │ │ ├── error.js │ │ ├── geographic.js │ │ └── user.js │ └── utils │ │ ├── Authorized.js │ │ ├── Yuan.js │ │ ├── authority.js │ │ ├── authority.test.js │ │ ├── request.js │ │ ├── utils.js │ │ ├── utils.less │ │ └── utils.test.js │ ├── tests │ └── run-tests.js │ ├── tsconfig.json │ └── tslint.json ├── Chapter2 ├── README.md ├── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ │ └── cas │ │ │ └── config │ │ │ ├── cas.properties │ │ │ └── log4j2.xml │ ├── maven │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── net │ │ │ └── anumbrella │ │ │ └── sso │ │ │ └── MyPasswordEncoder.java │ │ └── resources │ │ ├── application.properties │ │ ├── shiro.ini │ │ └── thekeystore └── restserver │ ├── .gitignore │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── net │ │ └── anumbrella │ │ └── rest │ │ └── server │ │ ├── Application.java │ │ ├── controller │ │ └── RestAuthController.java │ │ ├── entity │ │ └── SysUser.java │ │ └── util │ │ └── Base64Utils.java │ └── resources │ └── application.properties ├── Chapter3 ├── README.md └── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ └── cas │ │ └── config │ │ ├── cas.properties │ │ └── log4j2.xml │ ├── maven │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── net │ │ └── anumbrella │ │ └── sso │ │ ├── authentication │ │ ├── CustomUsernamePasswordAuthentication.java │ │ └── CustomerHandlerAuthentication.java │ │ ├── config │ │ └── CustomAuthenticationConfiguration.java │ │ └── entity │ │ └── User.java │ └── resources │ ├── META-INF │ └── spring.factories │ ├── application.properties │ ├── shiro.ini │ └── thekeystore ├── Chapter4 ├── README.md ├── cas-management-overlay │ ├── .gitignore │ ├── LICENSE.txt │ ├── README.md │ ├── build.cmd │ ├── build.sh │ ├── etc │ │ └── cas │ │ │ └── config │ │ │ ├── log4j2-management.xml │ │ │ ├── management.properties │ │ │ └── users.properties │ ├── maven │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ │ └── main │ │ └── resources │ │ ├── application.properties │ │ ├── thekeystore │ │ └── user-details.properties ├── cas-sample-java-webapp │ ├── .gitignore │ ├── README.md │ ├── etc │ │ └── jetty │ │ │ ├── jetty-https.xml │ │ │ ├── jetty-ssl.xml │ │ │ ├── jetty.xml │ │ │ └── web.xml │ ├── pom.xml │ └── src │ │ └── main │ │ ├── resources │ │ └── log4j.xml │ │ └── webapp │ │ ├── WEB-INF │ │ └── web.xml │ │ ├── index.jsp │ │ └── logout.jsp └── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ └── cas │ │ └── config │ │ ├── cas.properties │ │ └── log4j2.xml │ ├── maven │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── net │ │ └── anumbrella │ │ └── sso │ │ ├── authentication │ │ ├── CustomUsernamePasswordAuthentication.java │ │ └── CustomerHandlerAuthentication.java │ │ ├── config │ │ └── CustomAuthenticationConfiguration.java │ │ ├── controller │ │ └── ServicesManagerController.java │ │ └── entity │ │ └── User.java │ └── resources │ ├── META-INF │ └── spring.factories │ ├── application.properties │ ├── services │ ├── web-10000001.json │ └── web-10000001.yml │ ├── shiro.ini │ └── thekeystore ├── Chapter5 ├── README.md └── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ └── cas │ │ └── config │ │ ├── cas.properties │ │ └── log4j2.xml │ ├── maven │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── net │ │ └── anumbrella │ │ └── sso │ │ ├── authentication │ │ ├── CustomUsernamePasswordAuthentication.java │ │ └── CustomerHandlerAuthentication.java │ │ ├── config │ │ ├── CustomAuthenticationConfiguration.java │ │ ├── CustomWebflowConfigurer.java │ │ └── CustomerAuthWebflowConfiguration.java │ │ ├── controller │ │ └── ServicesManagerController.java │ │ └── entity │ │ ├── CustomCredential.java │ │ └── User.java │ └── resources │ ├── META-INF │ └── spring.factories │ ├── anumbrella.properties │ ├── application.properties │ ├── services │ ├── web-10000001.json │ └── web-10000001.yml │ ├── shiro.ini │ ├── static │ └── themes │ │ └── anumbrella │ │ ├── css │ │ └── cas.css │ │ ├── images │ │ └── po.jpeg │ │ └── js │ │ └── cas.js │ ├── templates │ └── anumbrella │ │ └── casLoginView.html │ └── thekeystore ├── Chapter6 ├── README.md └── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ └── cas │ │ └── config │ │ ├── cas.properties │ │ └── log4j2.xml │ ├── maven │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── net │ │ └── anumbrella │ │ └── sso │ │ ├── action │ │ └── ValidateLoginAction.java │ │ ├── authentication │ │ ├── CustomUsernamePasswordAuthentication.java │ │ └── CustomerHandlerAuthentication.java │ │ ├── config │ │ ├── CustomAuthenticationConfiguration.java │ │ ├── CustomControllerConfigurer.java │ │ ├── CustomWebflowConfigurer.java │ │ └── CustomerAuthWebflowConfiguration.java │ │ ├── controller │ │ ├── CaptchaController.java │ │ └── ServicesManagerController.java │ │ ├── entity │ │ ├── CustomCredential.java │ │ └── User.java │ │ ├── exection │ │ └── CheckCodeErrorException.java │ │ └── utils │ │ ├── CaptchaCodeUtils.java │ │ └── KaptchaCodeUtils.java │ └── resources │ ├── META-INF │ └── spring.factories │ ├── anumbrella.properties │ ├── application.properties │ ├── messages_zh_CN.properties │ ├── services │ ├── web-10000001.json │ └── web-10000001.yml │ ├── shiro.ini │ ├── static │ └── themes │ │ └── anumbrella │ │ ├── css │ │ └── cas.css │ │ ├── images │ │ └── po.jpeg │ │ └── js │ │ ├── cas.js │ │ └── code.js │ ├── templates │ └── anumbrella │ │ └── casLoginView.html │ └── thekeystore ├── Chapter7 ├── README.md ├── cas-management-overlay │ ├── .gitignore │ ├── LICENSE.txt │ ├── README.md │ ├── build.cmd │ ├── build.sh │ ├── etc │ │ └── cas │ │ │ └── config │ │ │ ├── log4j2-management.xml │ │ │ ├── management.properties │ │ │ └── users.properties │ ├── maven │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ │ └── main │ │ └── resources │ │ ├── application.properties │ │ ├── thekeystore │ │ └── user-details.properties ├── cas-sample-java-webapp │ ├── .gitignore │ ├── README.md │ ├── etc │ │ └── jetty │ │ │ ├── jetty-https.xml │ │ │ ├── jetty-ssl.xml │ │ │ ├── jetty.xml │ │ │ └── web.xml │ ├── pom.xml │ └── src │ │ └── main │ │ ├── resources │ │ └── log4j.xml │ │ └── webapp │ │ ├── WEB-INF │ │ └── web.xml │ │ ├── index.jsp │ │ └── logout.jsp ├── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ │ └── cas │ │ │ └── config │ │ │ ├── cas.properties │ │ │ └── log4j2.xml │ ├── maven │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── net │ │ │ └── anumbrella │ │ │ └── sso │ │ │ ├── action │ │ │ └── ValidateLoginAction.java │ │ │ ├── authentication │ │ │ ├── CustomUsernamePasswordAuthentication.java │ │ │ └── CustomerHandlerAuthentication.java │ │ │ ├── config │ │ │ ├── CustomAuthenticationConfiguration.java │ │ │ ├── CustomControllerConfigurer.java │ │ │ ├── CustomWebflowConfigurer.java │ │ │ └── CustomerAuthWebflowConfiguration.java │ │ │ ├── controller │ │ │ ├── CaptchaController.java │ │ │ └── ServicesManagerController.java │ │ │ ├── entity │ │ │ ├── CustomCredential.java │ │ │ └── User.java │ │ │ ├── exection │ │ │ └── CheckCodeErrorException.java │ │ │ └── utils │ │ │ ├── CaptchaCodeUtils.java │ │ │ └── KaptchaCodeUtils.java │ │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── anumbrella.properties │ │ ├── application.properties │ │ ├── messages_zh_CN.properties │ │ ├── services │ │ ├── web-10000001.json │ │ └── web-10000001.yml │ │ ├── shiro.ini │ │ ├── static │ │ └── themes │ │ │ └── anumbrella │ │ │ ├── css │ │ │ └── cas.css │ │ │ ├── images │ │ │ └── po.jpeg │ │ │ └── js │ │ │ ├── cas.js │ │ │ └── code.js │ │ ├── templates │ │ └── anumbrella │ │ │ └── casLoginView.html │ │ └── thekeystore └── restserver │ ├── .gitignore │ ├── pom.xml │ ├── src │ └── main │ │ ├── java │ │ └── net │ │ │ └── anumbrella │ │ │ └── rest │ │ │ └── server │ │ │ ├── Application.java │ │ │ ├── controller │ │ │ └── RestAttributeController.java │ │ │ ├── entity │ │ │ └── SysUser.java │ │ │ └── util │ │ │ └── Base64Utils.java │ │ └── resources │ │ └── application.properties │ └── target │ └── classes │ └── application.properties ├── Chapter8 ├── README.md ├── cas-sample-java-webapp │ ├── .gitignore │ ├── README.md │ ├── etc │ │ └── jetty │ │ │ ├── jetty-https.xml │ │ │ ├── jetty-ssl.xml │ │ │ ├── jetty.xml │ │ │ └── web.xml │ ├── pom.xml │ └── src │ │ └── main │ │ ├── resources │ │ └── log4j.xml │ │ └── webapp │ │ ├── WEB-INF │ │ └── web.xml │ │ ├── index.jsp │ │ └── logout.jsp ├── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ │ └── cas │ │ │ └── config │ │ │ ├── cas.properties │ │ │ └── log4j2.xml │ ├── maven │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── net │ │ │ └── anumbrella │ │ │ └── sso │ │ │ ├── action │ │ │ └── ValidateLoginAction.java │ │ │ ├── authentication │ │ │ ├── CustomUsernamePasswordAuthentication.java │ │ │ └── CustomerHandlerAuthentication.java │ │ │ ├── config │ │ │ ├── CustomAuthenticationConfiguration.java │ │ │ ├── CustomControllerConfigurer.java │ │ │ ├── CustomWebflowConfigurer.java │ │ │ └── CustomerAuthWebflowConfiguration.java │ │ │ ├── controller │ │ │ ├── CaptchaController.java │ │ │ └── ServicesManagerController.java │ │ │ ├── entity │ │ │ ├── CustomCredential.java │ │ │ └── User.java │ │ │ ├── exection │ │ │ └── CheckCodeErrorException.java │ │ │ └── utils │ │ │ ├── CaptchaCodeUtils.java │ │ │ └── KaptchaCodeUtils.java │ │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── anumbrella.properties │ │ ├── application.properties │ │ ├── messages_zh_CN.properties │ │ ├── services │ │ ├── web-10000001.json │ │ └── web-10000001.yml │ │ ├── shiro.ini │ │ ├── static │ │ └── themes │ │ │ └── anumbrella │ │ │ ├── css │ │ │ └── cas.css │ │ │ ├── images │ │ │ └── po.jpeg │ │ │ └── js │ │ │ ├── cas.js │ │ │ └── code.js │ │ ├── templates │ │ └── anumbrella │ │ │ └── casLoginView.html │ │ └── thekeystore └── client-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── net │ │ └── anumbrella │ │ └── sso │ │ ├── Application.java │ │ ├── config │ │ ├── CasCustomConfig.java │ │ ├── SpringCasAutoconfig.java │ │ └── WebSecurityConfig.java │ │ ├── controller │ │ └── IndexController.java │ │ ├── dao │ │ └── LoginDao.java │ │ ├── entity │ │ └── User.java │ │ └── service │ │ └── LoginService.java │ └── resources │ ├── application.properties │ └── templates │ ├── index.html │ └── login.html ├── Chapter9 ├── README.md ├── cas-sample-java-webapp │ ├── .gitignore │ ├── README.md │ ├── etc │ │ └── jetty │ │ │ ├── jetty-https.xml │ │ │ ├── jetty-ssl.xml │ │ │ ├── jetty.xml │ │ │ └── web.xml │ ├── pom.xml │ └── src │ │ └── main │ │ ├── resources │ │ └── log4j.xml │ │ └── webapp │ │ ├── WEB-INF │ │ └── web.xml │ │ ├── index.jsp │ │ └── logout.jsp └── cas-server │ ├── .gitignore │ ├── LICENSE.txt │ ├── build.cmd │ ├── build.sh │ ├── etc │ └── cas │ │ └── config │ │ ├── cas.properties │ │ └── log4j2.xml │ ├── maven │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.bat │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── net │ │ └── anumbrella │ │ └── sso │ │ ├── action │ │ └── ValidateLoginAction.java │ │ ├── authentication │ │ ├── CustomUsernamePasswordAuthentication.java │ │ └── CustomerHandlerAuthentication.java │ │ ├── config │ │ ├── CustomAuthenticationConfiguration.java │ │ ├── CustomControllerConfigurer.java │ │ ├── CustomWebflowConfigurer.java │ │ └── CustomerAuthWebflowConfiguration.java │ │ ├── controller │ │ ├── CaptchaController.java │ │ └── ServicesManagerController.java │ │ ├── entity │ │ ├── CustomCredential.java │ │ └── User.java │ │ ├── exection │ │ └── CheckCodeErrorException.java │ │ └── utils │ │ ├── CaptchaCodeUtils.java │ │ └── KaptchaCodeUtils.java │ └── resources │ ├── META-INF │ └── spring.factories │ ├── anumbrella.properties │ ├── application.properties │ ├── messages_zh_CN.properties │ ├── services │ ├── web-10000001.json │ └── web-10000001.yml │ ├── shiro.ini │ ├── static │ └── themes │ │ └── anumbrella │ │ ├── css │ │ └── cas.css │ │ ├── images │ │ └── po.jpeg │ │ └── js │ │ ├── cas.js │ │ └── code.js │ ├── templates │ └── anumbrella │ │ └── casLoginView.html │ └── thekeystore ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | .DS_Store 4 | target/* 5 | 6 | # Log file 7 | *.log 8 | 9 | # BlueJ files 10 | *.ctxt 11 | 12 | # Mobile Tools for Java (J2ME) 13 | .mtj.tmp/ 14 | 15 | # Package Files # 16 | *.jar 17 | *.war 18 | *.nar 19 | *.ear 20 | *.zip 21 | *.tar.gz 22 | *.rar 23 | 24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 25 | hs_err_pid* 26 | 27 | .idea 28 | overlays/* 29 | *.iml 30 | 31 | -------------------------------------------------------------------------------- /Chapter1/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(二)——[搭建基础服务](https://blog.csdn.net/anumbrella/article/details/81045885). -------------------------------------------------------------------------------- /Chapter1/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter1/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter1/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter1/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter1/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter10/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(十一)——[单点退出](https://blog.csdn.net/Anumbrella/article/details/89069445). -------------------------------------------------------------------------------- /Chapter10/cas-management-overlay/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | !/.project 3 | .project 4 | .settings 5 | target/ 6 | .idea/ 7 | .DS_Store 8 | .idea 9 | overlays/ 10 | .gradle/ 11 | build/ 12 | bin/ 13 | *.iml 14 | 15 | *.log.gz 16 | *.log -------------------------------------------------------------------------------- /Chapter10/cas-management-overlay/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function copy() { 5 | echo -e "Creating configuration directory under /etc/cas" 6 | mkdir -p /etc/cas/config 7 | 8 | echo -e "Copying configuration files from etc/cas to /etc/cas" 9 | cp -rfv etc/cas/* /etc/cas 10 | } 11 | 12 | function help() { 13 | echo "Usage: build.sh [copy|clean|package|run]" 14 | } 15 | 16 | function clean() { 17 | rm -Rf *.log 18 | rm -Rf *.log.gz 19 | ./mvnw clean "$@" 20 | } 21 | 22 | function package() { 23 | ./mvnw clean package -T 5 "$@" 24 | # copy 25 | } 26 | 27 | 28 | function run() { 29 | package && java -Xdebug -Xrunjdwp:transport=dt_socket,address=5000,server=y,suspend=n -jar target/cas-management.war 30 | } 31 | 32 | if [ $# -eq 0 ]; then 33 | echo -e "No commands provided. Defaulting to [run]\n" 34 | run 35 | exit 0 36 | fi 37 | 38 | 39 | case "$1" in 40 | "copy") 41 | copy 42 | ;; 43 | "clean") 44 | shift 45 | clean "$@" 46 | ;; 47 | "package") 48 | shift 49 | package "$@" 50 | ;; 51 | "run") 52 | run "$@" 53 | ;; 54 | *) 55 | help 56 | ;; 57 | esac 58 | 59 | -------------------------------------------------------------------------------- /Chapter10/cas-management-overlay/etc/cas/config/management.properties: -------------------------------------------------------------------------------- 1 | # CAS server that management app will authenticate with 2 | # This server will authenticate for any app (service) and you can login as casuser/Mellon 3 | cas.server.name: https://jasigcas.herokuapp.com 4 | cas.server.prefix: https://jasigcas.herokuapp.com/cas 5 | 6 | cas.mgmt.adminRoles[0]=ROLE_ADMIN 7 | cas.mgmt.userPropertiesFile=file:/etc/cas/config/users.properties 8 | 9 | # Update this URL to point at server running this management app 10 | cas.mgmt.serverName=https://mmoayyed.unicon.net:8443 11 | 12 | server.context-path=/cas-management 13 | server.port=8443 14 | 15 | logging.config=file:/etc/cas/config/log4j2-management.xml 16 | -------------------------------------------------------------------------------- /Chapter10/cas-management-overlay/etc/cas/config/users.properties: -------------------------------------------------------------------------------- 1 | # Only 'casuser' is authorized to use cas services management app 2 | casuser=notused,ROLE_ADMIN 3 | -------------------------------------------------------------------------------- /Chapter10/cas-management-overlay/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:36:18 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter10/cas-management-overlay/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter10/cas-management-overlay/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter10/cas-management-overlay/src/main/resources/user-details.properties: -------------------------------------------------------------------------------- 1 | casuser=notused,ROLE_ADMIN 2 | anumbrella=notused,ROLE_ADMIN -------------------------------------------------------------------------------- /Chapter10/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter10/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter10/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private String email; 13 | 14 | private int expired; 15 | 16 | private int disabled; 17 | 18 | public String getUsername() { 19 | return username; 20 | } 21 | 22 | public void setUsername(String username) { 23 | this.username = username; 24 | } 25 | 26 | public String getPassword() { 27 | return password; 28 | } 29 | 30 | public void setPassword(String password) { 31 | this.password = password; 32 | } 33 | 34 | public int getExpired() { 35 | return expired; 36 | } 37 | 38 | public void setExpired(int expired) { 39 | this.expired = expired; 40 | } 41 | 42 | public int getDisabled() { 43 | return disabled; 44 | } 45 | 46 | public void setDisabled(int disabled) { 47 | this.disabled = disabled; 48 | } 49 | 50 | public String getEmail() { 51 | return email; 52 | } 53 | 54 | public void setEmail(String email) { 55 | this.email = email; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/java/net/anumbrella/sso/exection/CheckCodeErrorException.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.exection; 2 | 3 | import org.apereo.cas.authentication.AuthenticationException; 4 | 5 | /** 6 | * @author Anumbrella 7 | */ 8 | public class CheckCodeErrorException extends AuthenticationException { 9 | 10 | 11 | public CheckCodeErrorException(){ 12 | super(); 13 | } 14 | 15 | 16 | public CheckCodeErrorException(String msg) { 17 | super(msg); 18 | } 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.anumbrella.sso.config.CustomAuthenticationConfiguration,\ 3 | net.anumbrella.sso.config.CustomerAuthWebflowConfiguration,\ 4 | net.anumbrella.sso.config.CustomControllerConfigurer -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/resources/anumbrella.properties: -------------------------------------------------------------------------------- 1 | anumbrella.javascript.file=/themes/anumbrella/js/cas.js 2 | anumbrella.standard.css.file=/themes/anumbrella/css/cas.css 3 | anumbrella.javascript.code.file=/themes/anumbrella/js/code.js 4 | 5 | anumbrella.login.images.path=/themes/anumbrella/images 6 | 7 | cas.standard.css.file=/css/cas.css 8 | cas.javascript.file=/js/cas.js 9 | cas.admin.css.file=/css/admin.css 10 | 11 | spring.thymeleaf.cache=false -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/resources/services/web-10000001.json: -------------------------------------------------------------------------------- 1 | { 2 | "@class" : "org.apereo.cas.services.RegexRegisteredService", 3 | "serviceId" : "^(https|imaps|http)://.*", 4 | "name" : "web", 5 | "id" : 10000001, 6 | "evaluationOrder" : 10, 7 | "accessStrategy" : { 8 | "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", 9 | "enabled" : true, 10 | "ssoEnabled" : true 11 | }, 12 | "attributeReleasePolicy": { 13 | "@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy" 14 | }, 15 | "theme": "anumbrella" 16 | } -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/resources/services/web-10000001.yml: -------------------------------------------------------------------------------- 1 | --- ! 2 | serviceId: "^(https|imaps|http)://.*" 3 | name: "web" 4 | id: 10000001 5 | description: "description" 6 | evaluationOrder: 10 7 | attributeReleasePolicy: ! {} 8 | accessStrategy: ! 9 | enabled: true 10 | ssoEnabled: true -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter10/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/resources/static/themes/anumbrella/js/code.js: -------------------------------------------------------------------------------- 1 | function changeCode(){ 2 | var node = document.getElementById("captcha_img"); 3 | var url = node.src; 4 | // 修改验证码 5 | if (node){ 6 | if(url.indexOf("?") >= 0){ 7 | node.src = url.split('?')[0] +'?id='+uuid(); 8 | }else{ 9 | node.src = url +'?id='+uuid(); 10 | } 11 | 12 | } 13 | } 14 | 15 | 16 | function uuid(){ 17 | //获取系统当前的时间 18 | var d = new Date().getTime(); 19 | //替换uuid里面的x和y 20 | var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 21 | //取余 16进制 22 | var r = (d + Math.random()*16)%16 | 0; 23 | //向下去整 24 | d = Math.floor(d/16); 25 | //toString 表示编程16进制的数据 26 | return (c=='x' ? r : (r&0x3|0x8)).toString(16); 27 | }); 28 | return uuid; 29 | }; -------------------------------------------------------------------------------- /Chapter10/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter10/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter10/client-demo/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter10/client-demo/src/main/java/net/anumbrella/sso/Application.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Chapter10/client-demo/src/main/java/net/anumbrella/sso/dao/LoginDao.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.dao; 2 | 3 | 4 | import net.anumbrella.sso.entity.User; 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author Anumbrella 12 | */ 13 | @Repository 14 | public interface LoginDao extends CrudRepository { 15 | 16 | List findByUsernameAndPassword(String name, String password); 17 | } -------------------------------------------------------------------------------- /Chapter10/client-demo/src/main/java/net/anumbrella/sso/service/LoginService.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.service; 2 | 3 | 4 | import net.anumbrella.sso.dao.LoginDao; 5 | import net.anumbrella.sso.entity.User; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author Anumbrella 13 | */ 14 | @Service 15 | public class LoginService { 16 | 17 | @Autowired 18 | private LoginDao loginDao; 19 | 20 | public boolean verifyLogin(User user) { 21 | 22 | List userList = loginDao.findByUsernameAndPassword(user.getUsername(), user.getPassword()); 23 | return userList.size() > 0; 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /Chapter10/client-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://localhost:3306/cas?characterEncoding=UTF-8&useUnicode=true 2 | spring.datasource.username=root 3 | spring.datasource.password=123 4 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 5 | spring.jpa.properties.hibernate.hbm2ddl.auto=update 6 | 7 | server.port=9443 8 | #你生成的证书名字 9 | server.ssl.key-store=/Users/anumbrella/keystore/thekeystore2 10 | #密钥库密码 11 | server.ssl.key-store-password=123456 12 | server.ssl.keyStoreType=JKS 13 | 14 | 15 | # 监听退出的接口,即所有接口都会进行监听 16 | spring.cas.sign-out-filters=/* 17 | # 需要拦截的认证的接口 18 | spring.cas.auth-filters=/* 19 | spring.cas.validate-filters=/* 20 | spring.cas.request-wrapper-filters=/* 21 | spring.cas.assertion-filters=/* 22 | # 表示忽略拦截的接口,也就是不用进行拦截 23 | spring.cas.ignore-filters=/test 24 | spring.cas.cas-server-login-url=https://sso.anumbrella.net:8443/cas/login 25 | spring.cas.cas-server-url-prefix=https://sso.anumbrella.net:8443/cas/ 26 | spring.cas.redirect-after-validation=true 27 | spring.cas.use-session=true 28 | spring.cas.server-name=https://client.anumbrella.net:9443 29 | -------------------------------------------------------------------------------- /Chapter10/client-demo/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 你好! 9 |
10 | 注销 11 | 12 | -------------------------------------------------------------------------------- /Chapter10/client-demo/src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | cas登录 7 | 12 | 13 | 14 |
15 |
16 |
    17 |
  • 18 | 19 |
    20 | 21 |
    22 |
  • 23 |
  • 24 | 25 |
    26 | 27 |
    28 |
  • 29 |
  • 30 |
    31 | 32 |
    33 |
  • 34 |
35 |
36 |
37 | 38 | -------------------------------------------------------------------------------- /Chapter11/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(十二)——[集群部署](https://blog.csdn.net/Anumbrella/article/details/90578300). -------------------------------------------------------------------------------- /Chapter11/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter11/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter11/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private String email; 13 | 14 | private int expired; 15 | 16 | private int disabled; 17 | 18 | public String getUsername() { 19 | return username; 20 | } 21 | 22 | public void setUsername(String username) { 23 | this.username = username; 24 | } 25 | 26 | public String getPassword() { 27 | return password; 28 | } 29 | 30 | public void setPassword(String password) { 31 | this.password = password; 32 | } 33 | 34 | public int getExpired() { 35 | return expired; 36 | } 37 | 38 | public void setExpired(int expired) { 39 | this.expired = expired; 40 | } 41 | 42 | public int getDisabled() { 43 | return disabled; 44 | } 45 | 46 | public void setDisabled(int disabled) { 47 | this.disabled = disabled; 48 | } 49 | 50 | public String getEmail() { 51 | return email; 52 | } 53 | 54 | public void setEmail(String email) { 55 | this.email = email; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/java/net/anumbrella/sso/exection/CheckCodeErrorException.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.exection; 2 | 3 | import org.apereo.cas.authentication.AuthenticationException; 4 | 5 | /** 6 | * @author Anumbrella 7 | */ 8 | public class CheckCodeErrorException extends AuthenticationException { 9 | 10 | 11 | public CheckCodeErrorException(){ 12 | super(); 13 | } 14 | 15 | 16 | public CheckCodeErrorException(String msg) { 17 | super(msg); 18 | } 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.anumbrella.sso.config.CustomAuthenticationConfiguration,\ 3 | net.anumbrella.sso.config.CustomerAuthWebflowConfiguration,\ 4 | net.anumbrella.sso.config.CustomControllerConfigurer -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/resources/anumbrella.properties: -------------------------------------------------------------------------------- 1 | anumbrella.javascript.file=/themes/anumbrella/js/cas.js 2 | anumbrella.standard.css.file=/themes/anumbrella/css/cas.css 3 | anumbrella.javascript.code.file=/themes/anumbrella/js/code.js 4 | 5 | anumbrella.login.images.path=/themes/anumbrella/images 6 | 7 | cas.standard.css.file=/css/cas.css 8 | cas.javascript.file=/js/cas.js 9 | cas.admin.css.file=/css/admin.css 10 | 11 | spring.thymeleaf.cache=false -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/resources/services/web-10000001.json: -------------------------------------------------------------------------------- 1 | { 2 | "@class" : "org.apereo.cas.services.RegexRegisteredService", 3 | "serviceId" : "^(https|imaps|http)://.*", 4 | "name" : "web", 5 | "id" : 10000001, 6 | "evaluationOrder" : 10, 7 | "accessStrategy" : { 8 | "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", 9 | "enabled" : true, 10 | "ssoEnabled" : true 11 | }, 12 | "attributeReleasePolicy": { 13 | "@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy" 14 | }, 15 | "theme": "anumbrella" 16 | } -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/resources/services/web-10000001.yml: -------------------------------------------------------------------------------- 1 | --- ! 2 | serviceId: "^(https|imaps|http)://.*" 3 | name: "web" 4 | id: 10000001 5 | description: "description" 6 | evaluationOrder: 10 7 | attributeReleasePolicy: ! {} 8 | accessStrategy: ! 9 | enabled: true 10 | ssoEnabled: true -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter11/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/resources/static/themes/anumbrella/js/code.js: -------------------------------------------------------------------------------- 1 | function changeCode(){ 2 | var node = document.getElementById("captcha_img"); 3 | var url = node.src; 4 | // 修改验证码 5 | if (node){ 6 | if(url.indexOf("?") >= 0){ 7 | node.src = url.split('?')[0] +'?id='+uuid(); 8 | }else{ 9 | node.src = url +'?id='+uuid(); 10 | } 11 | 12 | } 13 | } 14 | 15 | 16 | function uuid(){ 17 | //获取系统当前的时间 18 | var d = new Date().getTime(); 19 | //替换uuid里面的x和y 20 | var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 21 | //取余 16进制 22 | var r = (d + Math.random()*16)%16 | 0; 23 | //向下去整 24 | d = Math.floor(d/16); 25 | //toString 表示编程16进制的数据 26 | return (c=='x' ? r : (r&0x3|0x8)).toString(16); 27 | }); 28 | return uuid; 29 | }; -------------------------------------------------------------------------------- /Chapter11/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter11/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter12/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(十三)——[客户端前后端分离接入](https://blog.csdn.net/Anumbrella/article/details/94859351). -------------------------------------------------------------------------------- /Chapter12/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter12/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter12/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private String email; 13 | 14 | private int expired; 15 | 16 | private int disabled; 17 | 18 | public String getUsername() { 19 | return username; 20 | } 21 | 22 | public void setUsername(String username) { 23 | this.username = username; 24 | } 25 | 26 | public String getPassword() { 27 | return password; 28 | } 29 | 30 | public void setPassword(String password) { 31 | this.password = password; 32 | } 33 | 34 | public int getExpired() { 35 | return expired; 36 | } 37 | 38 | public void setExpired(int expired) { 39 | this.expired = expired; 40 | } 41 | 42 | public int getDisabled() { 43 | return disabled; 44 | } 45 | 46 | public void setDisabled(int disabled) { 47 | this.disabled = disabled; 48 | } 49 | 50 | public String getEmail() { 51 | return email; 52 | } 53 | 54 | public void setEmail(String email) { 55 | this.email = email; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/java/net/anumbrella/sso/exection/CheckCodeErrorException.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.exection; 2 | 3 | import org.apereo.cas.authentication.AuthenticationException; 4 | 5 | /** 6 | * @author Anumbrella 7 | */ 8 | public class CheckCodeErrorException extends AuthenticationException { 9 | 10 | 11 | public CheckCodeErrorException(){ 12 | super(); 13 | } 14 | 15 | 16 | public CheckCodeErrorException(String msg) { 17 | super(msg); 18 | } 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.anumbrella.sso.config.CustomAuthenticationConfiguration,\ 3 | net.anumbrella.sso.config.CustomerAuthWebflowConfiguration,\ 4 | net.anumbrella.sso.config.CustomControllerConfigurer -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/resources/anumbrella.properties: -------------------------------------------------------------------------------- 1 | anumbrella.javascript.file=/themes/anumbrella/js/cas.js 2 | anumbrella.standard.css.file=/themes/anumbrella/css/cas.css 3 | anumbrella.javascript.code.file=/themes/anumbrella/js/code.js 4 | 5 | anumbrella.login.images.path=/themes/anumbrella/images 6 | 7 | cas.standard.css.file=/css/cas.css 8 | cas.javascript.file=/js/cas.js 9 | cas.admin.css.file=/css/admin.css 10 | 11 | spring.thymeleaf.cache=false -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/resources/services/web-10000001.json: -------------------------------------------------------------------------------- 1 | { 2 | "@class" : "org.apereo.cas.services.RegexRegisteredService", 3 | "serviceId" : "^(https|imaps|http)://.*", 4 | "name" : "web", 5 | "id" : 10000001, 6 | "evaluationOrder" : 10, 7 | "accessStrategy" : { 8 | "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", 9 | "enabled" : true, 10 | "ssoEnabled" : true 11 | }, 12 | "attributeReleasePolicy": { 13 | "@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy" 14 | }, 15 | "theme": "anumbrella" 16 | } -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/resources/services/web-10000001.yml: -------------------------------------------------------------------------------- 1 | --- ! 2 | serviceId: "^(https|imaps|http)://.*" 3 | name: "web" 4 | id: 10000001 5 | description: "description" 6 | evaluationOrder: 10 7 | attributeReleasePolicy: ! {} 8 | accessStrategy: ! 9 | enabled: true 10 | ssoEnabled: true -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter12/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/resources/static/themes/anumbrella/js/code.js: -------------------------------------------------------------------------------- 1 | function changeCode(){ 2 | var node = document.getElementById("captcha_img"); 3 | var url = node.src; 4 | // 修改验证码 5 | if (node){ 6 | if(url.indexOf("?") >= 0){ 7 | node.src = url.split('?')[0] +'?id='+uuid(); 8 | }else{ 9 | node.src = url +'?id='+uuid(); 10 | } 11 | 12 | } 13 | } 14 | 15 | 16 | function uuid(){ 17 | //获取系统当前的时间 18 | var d = new Date().getTime(); 19 | //替换uuid里面的x和y 20 | var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 21 | //取余 16进制 22 | var r = (d + Math.random()*16)%16 | 0; 23 | //向下去整 24 | d = Math.floor(d/16); 25 | //toString 表示编程16进制的数据 26 | return (c=='x' ? r : (r&0x3|0x8)).toString(16); 27 | }); 28 | return uuid; 29 | }; -------------------------------------------------------------------------------- /Chapter12/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter12/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter12/client-demo/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter12/client-demo/src/main/java/net/anumbrella/sso/Application.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Chapter12/client-demo/src/main/java/net/anumbrella/sso/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.dao; 2 | 3 | 4 | import net.anumbrella.sso.entity.User; 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author Anumbrella 12 | */ 13 | @Repository 14 | public interface UserDao extends CrudRepository { 15 | 16 | List findByUsernameAndPassword(String name, String password); 17 | 18 | User findByUsername(String name); 19 | } -------------------------------------------------------------------------------- /Chapter12/client-demo/src/main/java/net/anumbrella/sso/entity/ResponseResult.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | public class ResponseResult implements Serializable { 6 | 7 | private String msg; 8 | 9 | private int code; 10 | 11 | public ResponseResult(String msg, int code) { 12 | this.code = code; 13 | this.msg = msg; 14 | } 15 | 16 | public String getMsg() { 17 | return msg; 18 | } 19 | 20 | public void setMsg(String msg) { 21 | this.msg = msg; 22 | } 23 | 24 | public int getCode() { 25 | return code; 26 | } 27 | 28 | public void setCode(int code) { 29 | this.code = code; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Chapter12/client-demo/src/main/java/net/anumbrella/sso/service/UserService.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.service; 2 | 3 | 4 | import net.anumbrella.sso.dao.UserDao; 5 | import net.anumbrella.sso.entity.User; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author Anumbrella 13 | */ 14 | @Service 15 | public class UserService { 16 | 17 | @Autowired 18 | private UserDao userDao; 19 | 20 | public List list() { 21 | return (List) userDao.findAll(); 22 | } 23 | 24 | public User findUserById(Long id){ 25 | return userDao.findOne(id); 26 | } 27 | 28 | public List findByUsernameAndPassword(String username, String password){ 29 | return userDao.findByUsernameAndPassword(username, password); 30 | } 31 | 32 | public User findByUsername(String username){ 33 | return userDao.findByUsername(username); 34 | } 35 | 36 | 37 | 38 | } -------------------------------------------------------------------------------- /Chapter12/client-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://localhost:3306/cas?characterEncoding=UTF-8&useUnicode=true 2 | spring.datasource.username=root 3 | spring.datasource.password=123 4 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 5 | spring.jpa.properties.hibernate.hbm2ddl.auto=update 6 | 7 | server.port=8080 8 | 9 | # 监听退出的接口,即所有接口都会进行监听 10 | spring.cas.sign-out-filters=/* 11 | # 需要拦截的认证的接口 12 | spring.cas.auth-filters=/* 13 | spring.cas.validate-filters=/* 14 | spring.cas.request-wrapper-filters=/* 15 | spring.cas.assertion-filters=/* 16 | # 表示忽略拦截的接口,也就是不用进行拦截 17 | spring.cas.ignore-filters=/api/user/info 18 | spring.cas.cas-server-login-url=https://sso.anumbrella.net:8443/cas/login 19 | spring.cas.cas-server-url-prefix=https://sso.anumbrella.net:8443/cas/ 20 | spring.cas.redirect-after-validation=true 21 | spring.cas.use-session=true 22 | # 使用url传递参数配置地址 23 | #spring.cas.server-name=http://client.anumbrella.net:8080 24 | # 使用nginx代理配置地址 25 | spring.cas.server-name=http://nginx.anumbrella.net:81 -------------------------------------------------------------------------------- /Chapter12/front-demo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | **/node_modules 5 | # roadhog-api-doc ignore 6 | /src/utils/request-temp.js 7 | _roadhog-api-doc 8 | 9 | # production 10 | /dist 11 | /.vscode 12 | 13 | # misc 14 | .DS_Store 15 | npm-debug.log* 16 | yarn-error.log 17 | 18 | /coverage 19 | .idea 20 | yarn.lock 21 | package-lock.json 22 | *bak 23 | .vscode 24 | 25 | # visual studio code 26 | .history 27 | *.log 28 | functions/* 29 | .temp/** 30 | 31 | # umi 32 | .umi 33 | .umi-production 34 | 35 | # screenshot 36 | screenshot 37 | .firebase 38 | .eslintcache 39 | 40 | build 41 | -------------------------------------------------------------------------------- /Chapter12/front-demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM circleci/node:latest-browsers 2 | 3 | WORKDIR /usr/src/app/ 4 | USER root 5 | COPY package.json ./ 6 | RUN yarn 7 | 8 | COPY ./ ./ 9 | 10 | RUN npm run test:all 11 | 12 | CMD ["npm", "run", "build"] 13 | -------------------------------------------------------------------------------- /Chapter12/front-demo/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | WORKDIR /usr/src/app/ 4 | 5 | COPY package.json ./ 6 | RUN npm install --silent --no-cache 7 | 8 | COPY ./ ./ 9 | 10 | 11 | CMD ["npm", "run", "start"] 12 | -------------------------------------------------------------------------------- /Chapter12/front-demo/Dockerfile.hub: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | WORKDIR /usr/src/app/ 4 | 5 | COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf 6 | 7 | COPY ./dist /usr/share/nginx/html/ 8 | 9 | EXPOSE 80 10 | 11 | CMD ["nginx", "-g", "daemon off;"] -------------------------------------------------------------------------------- /Chapter12/front-demo/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Alipay.inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Chapter12/front-demo/appveyor.yml: -------------------------------------------------------------------------------- 1 | # Test against the latest version of this Node.js version 2 | environment: 3 | nodejs_version: '10' 4 | 5 | # this is how to allow failing jobs in the matrix 6 | matrix: 7 | fast_finish: true # set this flag to immediately finish build once one of the jobs fails. 8 | 9 | # Install scripts. (runs after repo cloning) 10 | install: 11 | # Get the latest stable version of Node.js or io.js 12 | - ps: Install-Product node $env:nodejs_version 13 | # install modules 14 | - npm install 15 | # Output useful info for debugging. 16 | - node --version 17 | - npm --version 18 | 19 | # Post-install test scripts. 20 | test_script: 21 | - npm run lint 22 | - npm run test:all 23 | - npm run build 24 | 25 | # Don't actually build. 26 | build: off 27 | -------------------------------------------------------------------------------- /Chapter12/front-demo/config/plugin.config.js: -------------------------------------------------------------------------------- 1 | // Change theme plugin 2 | 3 | import MergeLessPlugin from 'antd-pro-merge-less'; 4 | import AntDesignThemePlugin from 'antd-theme-webpack-plugin'; 5 | import path from 'path'; 6 | 7 | export default config => { 8 | // pro 和 开发环境再添加这个插件 9 | if (process.env.APP_TYPE === 'site' || process.env.NODE_ENV !== 'production') { 10 | // 将所有 less 合并为一个供 themePlugin使用 11 | const outFile = path.join(__dirname, '../.temp/ant-design-pro.less'); 12 | const stylesDir = path.join(__dirname, '../src/'); 13 | 14 | config.plugin('merge-less').use(MergeLessPlugin, [ 15 | { 16 | stylesDir, 17 | outFile, 18 | }, 19 | ]); 20 | 21 | config.plugin('ant-design-theme').use(AntDesignThemePlugin, [ 22 | { 23 | antDir: path.join(__dirname, '../node_modules/antd'), 24 | stylesDir, 25 | varFile: path.join(__dirname, '../node_modules/antd/lib/style/themes/default.less'), 26 | mainLessFile: outFile, // themeVariables: ['@primary-color'], 27 | indexFileName: 'index.html', 28 | generateOne: true, 29 | lessUrl: 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js', 30 | }, 31 | ]); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /Chapter12/front-demo/config/router.config.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | // user 3 | { 4 | path: '/user', 5 | component: '../layouts/UserLayout', 6 | routes: [ 7 | { path: '/user', redirect: '/user/login' }, 8 | { path: '/user/login', component: './User/Login' }, 9 | ], 10 | }, 11 | // app 12 | { 13 | path: '/', 14 | Routes: ['src/pages/Authorized'], 15 | authority: ['admin', 'user'], 16 | routes: [ 17 | // home 18 | { path: '/', redirect: '/home' }, 19 | { path: '/home', component: './Home/Index' }, 20 | ], 21 | }, 22 | ]; 23 | -------------------------------------------------------------------------------- /Chapter12/front-demo/docker/docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | ant-design-pro_dev: 5 | ports: 6 | - 8000:8000 7 | build: 8 | context: ../ 9 | dockerfile: Dockerfile.dev 10 | container_name: "ant-design-pro_dev" 11 | volumes: 12 | - ../src:/usr/src/app/src 13 | - ../config:/usr/src/app/config 14 | - ../mock:/usr/src/app/mock 15 | -------------------------------------------------------------------------------- /Chapter12/front-demo/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | ant-design-pro_build: 5 | build: ../ 6 | container_name: "ant-design-pro_build" 7 | volumes: 8 | - dist:/usr/src/app/dist 9 | 10 | ant-design-pro_web: 11 | image: nginx 12 | ports: 13 | - 80:80 14 | container_name: "ant-design-pro_web" 15 | restart: unless-stopped 16 | volumes: 17 | - dist:/usr/share/nginx/html:ro 18 | - ./nginx.conf:/etc/nginx/conf.d/default.conf 19 | 20 | volumes: 21 | dist: 22 | -------------------------------------------------------------------------------- /Chapter12/front-demo/docker/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | # gzip config 4 | gzip on; 5 | gzip_min_length 1k; 6 | gzip_comp_level 9; 7 | gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml; 8 | gzip_vary on; 9 | gzip_disable "MSIE [1-6]\."; 10 | 11 | root /usr/share/nginx/html; 12 | 13 | location / { 14 | try_files $uri $uri/ /index.html; 15 | } 16 | location /api { 17 | proxy_pass https://preview.pro.ant.design; 18 | proxy_set_header X-Forwarded-Proto $scheme; 19 | proxy_set_header Host $http_host; 20 | proxy_set_header X-Real-IP $remote_addr; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Chapter12/front-demo/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "dist", 4 | "rewrites": [ 5 | { "source": "/api/**", "function": "api" }, 6 | { 7 | "source": "**", 8 | "destination": "/index.html" 9 | } 10 | ], 11 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Chapter12/front-demo/jest-puppeteer.config.js: -------------------------------------------------------------------------------- 1 | // ps https://github.com/GoogleChrome/puppeteer/issues/3120 2 | module.exports = { 3 | launch: { 4 | headless: true, 5 | args: [ 6 | '--disable-gpu', 7 | '--disable-dev-shm-usage', 8 | '--disable-setuid-sandbox', 9 | '--no-first-run', 10 | '--no-sandbox', 11 | '--no-zygote', 12 | '--single-process', 13 | ], 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /Chapter12/front-demo/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testURL: 'http://localhost:8000', 3 | preset: 'jest-puppeteer', 4 | }; 5 | -------------------------------------------------------------------------------- /Chapter12/front-demo/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["./src/*"] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter12/front-demo/mock/geographic.js: -------------------------------------------------------------------------------- 1 | import city from './geographic/city.json'; 2 | import province from './geographic/province.json'; 3 | 4 | function getProvince(req, res) { 5 | return res.json(province); 6 | } 7 | 8 | function getCity(req, res) { 9 | return res.json(city[req.params.province]); 10 | } 11 | 12 | export default { 13 | 'GET /api/geographic/province': getProvince, 14 | 'GET /api/geographic/city/:province': getCity, 15 | }; 16 | -------------------------------------------------------------------------------- /Chapter12/front-demo/mock/route.js: -------------------------------------------------------------------------------- 1 | export default { 2 | '/api/auth_routes': { 3 | '/form/advanced-form': { authority: ['admin', 'user'] }, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /Chapter12/front-demo/netlify.toml: -------------------------------------------------------------------------------- 1 | [[redirects]] 2 | from = "/api/*" 3 | to = "https://us-central1-antd-pro.cloudfunctions.net/api/api/:splat" 4 | status = 200 5 | force = true 6 | [redirects.headers] 7 | X-From = "Netlify" 8 | X-Api-Key = "some-api-key-string" 9 | 10 | [[redirects]] 11 | from = "/*" 12 | to = "/index.html" 13 | status = 200 -------------------------------------------------------------------------------- /Chapter12/front-demo/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter12/front-demo/public/favicon.png -------------------------------------------------------------------------------- /Chapter12/front-demo/public/icons/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter12/front-demo/public/icons/icon-128x128.png -------------------------------------------------------------------------------- /Chapter12/front-demo/public/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter12/front-demo/public/icons/icon-192x192.png -------------------------------------------------------------------------------- /Chapter12/front-demo/public/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter12/front-demo/public/icons/icon-512x512.png -------------------------------------------------------------------------------- /Chapter12/front-demo/scripts/generateMock.js: -------------------------------------------------------------------------------- 1 | const generateMock = require('merge-umi-mock-data'); 2 | const path = require('path'); 3 | generateMock(path.join(__dirname, '../mock'), path.join(__dirname, '../functions/mock/index.js')); 4 | -------------------------------------------------------------------------------- /Chapter12/front-demo/scripts/getPrettierFiles.js: -------------------------------------------------------------------------------- 1 | const glob = require('glob'); 2 | 3 | const getPrettierFiles = () => { 4 | let files = []; 5 | const jsFiles = glob.sync('src/**/*.js*', { ignore: ['**/node_modules/**', 'build/**'] }); 6 | const tsFiles = glob.sync('src/**/*.ts*', { ignore: ['**/node_modules/**', 'build/**'] }); 7 | const configFiles = glob.sync('config/**/*.js*', { ignore: ['**/node_modules/**', 'build/**'] }); 8 | const scriptFiles = glob.sync('scripts/**/*.js'); 9 | const lessFiles = glob.sync('src/**/*.less*', { ignore: ['**/node_modules/**', 'build/**'] }); 10 | files = files.concat(jsFiles); 11 | files = files.concat(tsFiles); 12 | files = files.concat(configFiles); 13 | files = files.concat(scriptFiles); 14 | files = files.concat(lessFiles); 15 | if (!files.length) { 16 | return; 17 | } 18 | return files; 19 | }; 20 | 21 | module.exports = getPrettierFiles; 22 | -------------------------------------------------------------------------------- /Chapter12/front-demo/scripts/prettier.js: -------------------------------------------------------------------------------- 1 | /** 2 | * copy to https://github.com/facebook/react/blob/master/scripts/prettier/index.js 3 | * prettier api doc https://prettier.io/docs/en/api.html 4 | *----------*****-------------- 5 | * prettier all js and all ts. 6 | *----------*****-------------- 7 | */ 8 | 9 | const prettier = require('prettier'); 10 | const fs = require('fs'); 11 | const getPrettierFiles = require('./getPrettierFiles'); 12 | const prettierConfigPath = require.resolve('../.prettierrc'); 13 | const chalk = require('chalk'); 14 | 15 | let didError = false; 16 | 17 | const files = getPrettierFiles(); 18 | 19 | files.forEach(file => { 20 | const options = prettier.resolveConfig.sync(file, { 21 | config: prettierConfigPath, 22 | }); 23 | const fileInfo = prettier.getFileInfo.sync(file); 24 | if (fileInfo.ignored) { 25 | return; 26 | } 27 | try { 28 | const input = fs.readFileSync(file, 'utf8'); 29 | const withParserOptions = { 30 | ...options, 31 | parser: fileInfo.inferredParser, 32 | }; 33 | const output = prettier.format(input, withParserOptions); 34 | if (output !== input) { 35 | fs.writeFileSync(file, output, 'utf8'); 36 | console.log(chalk.green(`${file} is prettier`)); 37 | } 38 | } catch (e) { 39 | didError = true; 40 | } 41 | }); 42 | 43 | if (didError) { 44 | process.exit(1); 45 | } 46 | console.log(chalk.hex('#1890FF')('prettier success!')); 47 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/app.js: -------------------------------------------------------------------------------- 1 | import fetch from 'dva/fetch'; 2 | 3 | export const dva = { 4 | config: { 5 | onError(err) { 6 | err.preventDefault(); 7 | }, 8 | }, 9 | }; 10 | 11 | let authRoutes = null; 12 | 13 | function ergodicRoutes(routes, authKey, authority) { 14 | routes.forEach(element => { 15 | if (element.path === authKey) { 16 | Object.assign(element.authority, authority || []); 17 | } else if (element.routes) { 18 | ergodicRoutes(element.routes, authKey, authority); 19 | } 20 | return element; 21 | }); 22 | } 23 | 24 | export function patchRoutes(routes) { 25 | Object.keys(authRoutes).map(authKey => 26 | ergodicRoutes(routes, authKey, authRoutes[authKey].authority) 27 | ); 28 | window.g_routes = routes; 29 | } 30 | 31 | export function render(oldRender) { 32 | fetch('/api/auth_routes') 33 | .then(res => res.json()) 34 | .then(ret => { 35 | authRoutes = ret; 36 | oldRender(); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/Authorized.js: -------------------------------------------------------------------------------- 1 | import CheckPermissions from './CheckPermissions'; 2 | 3 | const Authorized = ({ children, authority, noMatch = null }) => { 4 | const childrenRender = typeof children === 'undefined' ? null : children; 5 | return CheckPermissions(authority, childrenRender, noMatch); 6 | }; 7 | 8 | export default Authorized; 9 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/AuthorizedRoute.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { RouteProps } from 'react-router'; 3 | 4 | type authorityFN = (currentAuthority?: string) => boolean; 5 | 6 | type authority = string | string[] | authorityFN | Promise; 7 | 8 | export interface IAuthorizedRouteProps extends RouteProps { 9 | authority: authority; 10 | } 11 | export { authority }; 12 | 13 | export class AuthorizedRoute extends React.Component {} 14 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/AuthorizedRoute.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, Redirect } from 'react-router-dom'; 3 | import Authorized from './Authorized'; 4 | 5 | // TODO: umi只会返回render和rest 6 | const AuthorizedRoute = ({ component: Component, render, authority, redirectPath, ...rest }) => ( 7 | } />} 10 | > 11 | (Component ? : render(props))} /> 12 | 13 | ); 14 | 15 | export default AuthorizedRoute; 16 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/demo/AuthorizedArray.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: 4 | zh-CN: 使用数组作为参数 5 | en-US: Use Array as a parameter 6 | --- 7 | 8 | Use Array as a parameter 9 | 10 | ```jsx 11 | import RenderAuthorized from 'ant-design-pro/lib/Authorized'; 12 | import { Alert } from 'antd'; 13 | 14 | const Authorized = RenderAuthorized('user'); 15 | const noMatch = ; 16 | 17 | ReactDOM.render( 18 | 19 | 20 | , 21 | mountNode, 22 | ); 23 | ``` 24 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/demo/AuthorizedFunction.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | title: 4 | zh-CN: 使用方法作为参数 5 | en-US: Use function as a parameter 6 | --- 7 | 8 | Use Function as a parameter 9 | 10 | ```jsx 11 | import RenderAuthorized from 'ant-design-pro/lib/Authorized'; 12 | import { Alert } from 'antd'; 13 | 14 | const Authorized = RenderAuthorized('user'); 15 | const noMatch = ; 16 | 17 | const havePermission = () => { 18 | return false; 19 | }; 20 | 21 | ReactDOM.render( 22 | 23 | 28 | , 29 | mountNode, 30 | ); 31 | ``` 32 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 基本使用 5 | en-US: Basic use 6 | --- 7 | 8 | Basic use 9 | 10 | ```jsx 11 | import RenderAuthorized from 'ant-design-pro/lib/Authorized'; 12 | import { Alert } from 'antd'; 13 | 14 | const Authorized = RenderAuthorized('user'); 15 | const noMatch = ; 16 | 17 | ReactDOM.render( 18 |
19 | 20 | 21 | 22 |
, 23 | mountNode, 24 | ); 25 | ``` 26 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/demo/secured.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | title: 4 | zh-CN: 注解基本使用 5 | en-US: Basic use secured 6 | --- 7 | 8 | secured demo used 9 | 10 | ```jsx 11 | import RenderAuthorized from 'ant-design-pro/lib/Authorized'; 12 | import { Alert } from 'antd'; 13 | 14 | const { Secured } = RenderAuthorized('user'); 15 | 16 | @Secured('admin') 17 | class TestSecuredString extends React.Component { 18 | render() { 19 | ; 20 | } 21 | } 22 | ReactDOM.render( 23 |
24 | 25 |
, 26 | mountNode, 27 | ); 28 | ``` 29 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import AuthorizedRoute, { authority } from './AuthorizedRoute'; 3 | export type IReactComponent

= 4 | | React.StatelessComponent

5 | | React.ComponentClass

6 | | React.ClassicComponentClass

; 7 | 8 | type Secured = ( 9 | authority: authority, 10 | error?: React.ReactNode 11 | ) => (target: T) => T; 12 | 13 | type check = ( 14 | authority: authority, 15 | target: T, 16 | Exception: S 17 | ) => T | S; 18 | 19 | export interface IAuthorizedProps { 20 | authority: authority; 21 | noMatch?: React.ReactNode; 22 | } 23 | 24 | export class Authorized extends React.Component { 25 | public static Secured: Secured; 26 | public static AuthorizedRoute: typeof AuthorizedRoute; 27 | public static check: check; 28 | } 29 | 30 | declare function renderAuthorize(currentAuthority: string): typeof Authorized; 31 | 32 | export default renderAuthorize; 33 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/index.js: -------------------------------------------------------------------------------- 1 | import Authorized from './Authorized'; 2 | import AuthorizedRoute from './AuthorizedRoute'; 3 | import Secured from './Secured'; 4 | import check from './CheckPermissions'; 5 | import renderAuthorize from './renderAuthorize'; 6 | 7 | Authorized.Secured = Secured; 8 | Authorized.AuthorizedRoute = AuthorizedRoute; 9 | Authorized.check = check; 10 | 11 | export default renderAuthorize(Authorized); 12 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Authorized/renderAuthorize.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-mutable-exports */ 2 | let CURRENT = 'NULL'; 3 | /** 4 | * use authority or getAuthority 5 | * @param {string|()=>String} currentAuthority 6 | */ 7 | const renderAuthorize = Authorized => currentAuthority => { 8 | if (currentAuthority) { 9 | if (typeof currentAuthority === 'function') { 10 | CURRENT = currentAuthority(); 11 | } 12 | if ( 13 | Object.prototype.toString.call(currentAuthority) === '[object String]' || 14 | Array.isArray(currentAuthority) 15 | ) { 16 | CURRENT = currentAuthority; 17 | } 18 | } else { 19 | CURRENT = 'NULL'; 20 | } 21 | return Authorized; 22 | }; 23 | 24 | export { CURRENT }; 25 | export default Authorized => renderAuthorize(Authorized); 26 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Exception/demo/403.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | title: 4 | zh-CN: 403 5 | en-US: 403 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 403 页面,配合自定义操作。 11 | 12 | ## en-US 13 | 14 | 403 page with custom operations. 15 | 16 | ````jsx 17 | import Exception from 'ant-design-pro/lib/Exception'; 18 | import { Button } from 'antd'; 19 | 20 | const actions = ( 21 |

22 | 23 | 24 |
25 | ); 26 | ReactDOM.render( 27 | 28 | , mountNode); 29 | ```` 30 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Exception/demo/404.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 404 5 | en-US: 404 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 404 页面。 11 | 12 | ## en-US 13 | 14 | 404 page. 15 | 16 | ````jsx 17 | import Exception from 'ant-design-pro/lib/Exception'; 18 | 19 | ReactDOM.render( 20 | 21 | , mountNode); 22 | ```` 23 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Exception/demo/500.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: 4 | zh-CN: 500 5 | en-US: 500 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 500 页面。 11 | 12 | ## en-US 13 | 14 | 500 page. 15 | 16 | ````jsx 17 | import Exception from 'ant-design-pro/lib/Exception'; 18 | 19 | ReactDOM.render( 20 | 21 | , mountNode); 22 | ```` 23 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Exception/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IExceptionProps { 3 | type?: '403' | '404' | '500'; 4 | title?: React.ReactNode; 5 | desc?: React.ReactNode; 6 | img?: string; 7 | actions?: React.ReactNode; 8 | linkElement?: string | React.ComponentType; 9 | style?: React.CSSProperties; 10 | className?: string; 11 | backText?: React.ReactNode; 12 | redirect?: string; 13 | } 14 | 15 | export default class Exception extends React.Component {} 16 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Exception/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Exception 3 | cols: 1 4 | order: 5 5 | --- 6 | 7 | Exceptions page is used to provide feedback on specific abnormal state. Usually, it contains an explanation of the error status, and provides users with suggestions or operations, to prevent users from feeling lost and confused. 8 | 9 | ## API 10 | 11 | Property | Description | Type | Default 12 | ---------|-------------|------|-------- 13 | | backText | default return button text | ReactNode | back to home | 14 | type | type of exception, the corresponding default `title`, `desc`, `img` will be given if set, which can be overridden by explicit setting of `title`, `desc`, `img` | Enum {'403', '404', '500'} | - 15 | title | title | ReactNode | - 16 | desc | supplementary description | ReactNode | - 17 | img | the url of background image | string | - 18 | actions | suggested operations, a default 'Home' link will show if not set | ReactNode | - 19 | linkElement | to specify the element of link | string\|ReactElement | 'a' 20 | redirect | redirect path | string | '/' -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Exception/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Exception 3 | subtitle: 异常 4 | cols: 1 5 | order: 5 6 | --- 7 | 8 | 异常页用于对页面特定的异常状态进行反馈。通常,它包含对错误状态的阐述,并向用户提供建议或操作,避免用户感到迷失和困惑。 9 | 10 | ## API 11 | 12 | | 参数 | 说明| 类型 | 默认值 | 13 | |-------------|------------------------------------------|-------------|-------| 14 | | backText| 默认的返回按钮文本 | ReactNode| back to home | 15 | | type| 页面类型,若配置,则自带对应类型默认的 `title`,`desc`,`img`,此默认设置可以被 `title`,`desc`,`img` 覆盖 | Enum {'403', '404', '500'} | - | 16 | | title | 标题 | ReactNode| -| 17 | | desc| 补充描述| ReactNode| -| 18 | | img | 背景图片地址 | string| -| 19 | | actions | 建议操作,配置此属性时默认的『返回首页』按钮不生效| ReactNode| -| 20 | | linkElement | 定义链接的元素 | string\|ReactElement | 'a' | 21 | | redirect | 返回按钮的跳转地址 | string | '/' 22 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Exception/typeConfig.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | 403: { 3 | img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg', 4 | title: '403', 5 | desc: '抱歉,你无权访问该页面', 6 | }, 7 | 404: { 8 | img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg', 9 | title: '404', 10 | desc: '抱歉,你访问的页面不存在', 11 | }, 12 | 500: { 13 | img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg', 14 | title: '500', 15 | desc: '抱歉,服务器出错了', 16 | }, 17 | }; 18 | 19 | export default config; 20 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Login/LoginItem.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface ILoginItemProps { 3 | name?: string; 4 | rules?: any[]; 5 | style?: React.CSSProperties; 6 | onGetCaptcha?: () => void; 7 | placeholder?: string; 8 | buttonText?: React.ReactNode; 9 | } 10 | 11 | export class LoginItem extends React.Component {} 12 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/components/Login/LoginSubmit.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { Button, Form } from 'antd'; 4 | import styles from './index.less'; 5 | 6 | const FormItem = Form.Item; 7 | 8 | const LoginSubmit = ({ className, ...rest }) => { 9 | const clsString = classNames(styles.submit, className); 10 | return ( 11 | 12 | 35 | 38 | 41 | 44 | 45 | 46 | ); 47 | } 48 | } 49 | 50 | export default TriggerException; 51 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/pages/Exception/models/error.js: -------------------------------------------------------------------------------- 1 | import queryError from '@/services/error'; 2 | 3 | export default { 4 | namespace: 'error', 5 | 6 | state: { 7 | error: '', 8 | isloading: false, 9 | }, 10 | 11 | effects: { 12 | *query({ payload }, { call, put }) { 13 | yield call(queryError, payload.code); 14 | yield put({ 15 | type: 'trigger', 16 | payload: payload.code, 17 | }); 18 | }, 19 | }, 20 | 21 | reducers: { 22 | trigger(state, action) { 23 | return { 24 | error: action.payload, 25 | }; 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/pages/Exception/style.less: -------------------------------------------------------------------------------- 1 | .trigger { 2 | background: 'red'; 3 | :global(.ant-btn) { 4 | margin-right: 8px; 5 | margin-bottom: 12px; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/pages/Home/Index.less: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | padding: 0 auto; 3 | width: 90%; 4 | margin: 0 auto; 5 | } 6 | 7 | .avatar { 8 | text-align : center; 9 | margin-bottom: 24px; 10 | 11 | > img { 12 | width : 90px; 13 | height : 90px; 14 | } 15 | } 16 | 17 | .detail { 18 | margin-top: 8px; 19 | padding-left: 16px; 20 | > span { 21 | display: block; 22 | padding: 8px; 23 | margin-left: 16px; 24 | } 25 | } 26 | 27 | .modify_pass { 28 | margin-left: 40px; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/pages/User/Login.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .main { 4 | width: 368px; 5 | margin: 0 auto; 6 | @media screen and (max-width: @screen-sm) { 7 | width: 95%; 8 | } 9 | 10 | .icon { 11 | font-size: 24px; 12 | color: rgba(0, 0, 0, 0.2); 13 | margin-left: 16px; 14 | vertical-align: middle; 15 | cursor: pointer; 16 | transition: color 0.3s; 17 | 18 | &:hover { 19 | color: @primary-color; 20 | } 21 | } 22 | 23 | .other { 24 | text-align: left; 25 | margin-top: 24px; 26 | line-height: 22px; 27 | 28 | .register { 29 | float: right; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/pages/document.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CAS demo 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/services/api.js: -------------------------------------------------------------------------------- 1 | import { stringify } from 'qs'; 2 | import request from '@/utils/request'; 3 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/services/error.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export default async function queryError(code) { 4 | return request(`/api/${code}`); 5 | } 6 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/services/geographic.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export async function queryProvince() { 4 | return request('/api/geographic/province'); 5 | } 6 | 7 | export async function queryCity(province) { 8 | return request(`/api/geographic/city/${province}`); 9 | } 10 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/services/user.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export async function login(params) { 4 | return request('/api/user/login', { 5 | method: 'POST', 6 | body: params, 7 | }); 8 | } 9 | 10 | export async function authinfo() { 11 | return request('/api/user/info'); 12 | } 13 | 14 | export async function logout(params) { 15 | const { id } = params; 16 | return request(`/api/user/logout/${id}`); 17 | } -------------------------------------------------------------------------------- /Chapter12/front-demo/src/utils/Authorized.js: -------------------------------------------------------------------------------- 1 | import RenderAuthorized from '@/components/Authorized'; 2 | import { getAuthority } from './authority'; 3 | 4 | let Authorized = RenderAuthorized(getAuthority()); // eslint-disable-line 5 | 6 | // Reload the rights component 7 | const reloadAuthorized = () => { 8 | Authorized = RenderAuthorized(getAuthority()); 9 | }; 10 | 11 | export { reloadAuthorized }; 12 | export default Authorized; 13 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/utils/Yuan.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { yuan } from '@/components/Charts'; 3 | /** 4 | * 减少使用 dangerouslySetInnerHTML 5 | */ 6 | export default class Yuan extends React.PureComponent { 7 | componentDidMount() { 8 | this.rendertoHtml(); 9 | } 10 | 11 | componentDidUpdate() { 12 | this.rendertoHtml(); 13 | } 14 | 15 | rendertoHtml = () => { 16 | const { children } = this.props; 17 | if (this.main) { 18 | this.main.innerHTML = yuan(children); 19 | } 20 | }; 21 | 22 | render() { 23 | return ( 24 | { 26 | this.main = ref; 27 | }} 28 | /> 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/utils/authority.js: -------------------------------------------------------------------------------- 1 | // use localStorage to store the authority info, which might be sent from server in actual project. 2 | export function getAuthority(str) { 3 | // return localStorage.getItem('antd-pro-authority') || ['admin', 'user']; 4 | const authorityString = 5 | typeof str === 'undefined' ? localStorage.getItem('antd-pro-authority') : str; 6 | // authorityString could be admin, "admin", ["admin"] 7 | let authority; 8 | try { 9 | authority = JSON.parse(authorityString); 10 | } catch (e) { 11 | authority = authorityString; 12 | } 13 | if (typeof authority === 'string') { 14 | return [authority]; 15 | } 16 | return authority || ['admin']; 17 | } 18 | 19 | export function setAuthority(authority) { 20 | const proAuthority = typeof authority === 'string' ? [authority] : authority; 21 | return localStorage.setItem('antd-pro-authority', JSON.stringify(proAuthority)); 22 | } 23 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/utils/authority.test.js: -------------------------------------------------------------------------------- 1 | import { getAuthority } from './authority'; 2 | 3 | describe('getAuthority should be strong', () => { 4 | it('empty', () => { 5 | expect(getAuthority(null)).toEqual(['admin']); // default value 6 | }); 7 | it('string', () => { 8 | expect(getAuthority('admin')).toEqual(['admin']); 9 | }); 10 | it('array with double quotes', () => { 11 | expect(getAuthority('"admin"')).toEqual(['admin']); 12 | }); 13 | it('array with single item', () => { 14 | expect(getAuthority('["admin"]')).toEqual(['admin']); 15 | }); 16 | it('array with multiple items', () => { 17 | expect(getAuthority('["admin", "guest"]')).toEqual(['admin', 'guest']); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /Chapter12/front-demo/src/utils/utils.less: -------------------------------------------------------------------------------- 1 | .textOverflow() { 2 | overflow: hidden; 3 | text-overflow: ellipsis; 4 | word-break: break-all; 5 | white-space: nowrap; 6 | } 7 | 8 | .textOverflowMulti(@line: 3, @bg: #fff) { 9 | overflow: hidden; 10 | position: relative; 11 | line-height: 1.5em; 12 | max-height: @line * 1.5em; 13 | text-align: justify; 14 | margin-right: -1em; 15 | padding-right: 1em; 16 | &:before { 17 | background: @bg; 18 | content: '...'; 19 | padding: 0 1px; 20 | position: absolute; 21 | right: 14px; 22 | bottom: 0; 23 | } 24 | &:after { 25 | background: white; 26 | content: ''; 27 | margin-top: 0.2em; 28 | position: absolute; 29 | right: 14px; 30 | width: 1em; 31 | height: 1em; 32 | } 33 | } 34 | 35 | // mixins for clearfix 36 | // ------------------------ 37 | .clearfix() { 38 | zoom: 1; 39 | &:before, 40 | &:after { 41 | content: ' '; 42 | display: table; 43 | } 44 | &:after { 45 | clear: both; 46 | visibility: hidden; 47 | font-size: 0; 48 | height: 0; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Chapter12/front-demo/tests/run-tests.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const { spawn } = require('child_process'); 3 | const { kill } = require('cross-port-killer'); 4 | 5 | const env = Object.create(process.env); 6 | env.BROWSER = 'none'; 7 | env.TEST = true; 8 | // flag to prevent multiple test 9 | let once = false; 10 | 11 | const startServer = spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['start'], { 12 | env, 13 | }); 14 | 15 | startServer.stderr.on('data', data => { 16 | // eslint-disable-next-line 17 | console.log(data.toString()); 18 | }); 19 | 20 | startServer.on('exit', () => { 21 | kill(process.env.PORT || 8000); 22 | }); 23 | 24 | console.log('Starting development server for e2e tests...'); 25 | startServer.stdout.on('data', data => { 26 | console.log(data.toString()); 27 | if (!once && data.toString().indexOf('Compiled successfully') >= 0) { 28 | // eslint-disable-next-line 29 | once = true; 30 | console.log('Development server is started, ready to run tests.'); 31 | const testCmd = spawn( 32 | /^win/.test(process.platform) ? 'npm.cmd' : 'npm', 33 | ['test', '--', '--maxWorkers=1', '--runInBand'], 34 | { 35 | stdio: 'inherit', 36 | } 37 | ); 38 | testCmd.on('exit', code => { 39 | startServer.kill(); 40 | process.exit(code); 41 | }); 42 | } 43 | }); 44 | -------------------------------------------------------------------------------- /Chapter12/front-demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "build/dist", 4 | "module": "esnext", 5 | "target": "es2016", 6 | "lib": ["es6", "dom"], 7 | "sourceMap": true, 8 | "baseUrl": ".", 9 | "jsx": "react", 10 | "allowSyntheticDefaultImports": true, 11 | "moduleResolution": "node", 12 | "rootDirs": ["/src", "/test", "/mock","./typings"], 13 | "forceConsistentCasingInFileNames": true, 14 | "noImplicitReturns": true, 15 | "suppressImplicitAnyIndexErrors": true, 16 | "noUnusedLocals": true, 17 | "allowJs": true, 18 | "experimentalDecorators": true, 19 | "paths": { 20 | "@/*": ["./src/*"] 21 | } 22 | }, 23 | "include": ["./src"], 24 | "exclude": [ 25 | "node_modules", 26 | "build", 27 | "scripts", 28 | "acceptance-tests", 29 | "webpack", 30 | "jest", 31 | "src/setupTests.ts", 32 | "tslint:latest", 33 | "tslint-config-prettier" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /Chapter12/front-demo/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:latest", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "no-var-requires": false, 5 | "no-submodule-imports": false, 6 | "object-literal-sort-keys": false, 7 | "jsx-no-lambda": false, 8 | "no-implicit-dependencies": false, 9 | "no-console": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter2/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(三)——[多种认证方式](https://blog.csdn.net/anumbrella/article/details/81149249). 7 | -------------------------------------------------------------------------------- /Chapter2/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter2/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter2/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter2/cas-server/src/main/java/net/anumbrella/sso/MyPasswordEncoder.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso; 2 | 3 | import org.springframework.security.crypto.password.PasswordEncoder; 4 | 5 | /** 6 | * @author anumbrella 7 | */ 8 | public class MyPasswordEncoder implements PasswordEncoder { 9 | 10 | @Override 11 | public String encode(CharSequence charSequence) { 12 | // charSequence为输入的用户密码 13 | return charSequence.toString(); 14 | } 15 | 16 | @Override 17 | public boolean matches(CharSequence charSequence, String str) { 18 | // 当encode方法返回不为null时,matches方法才会调用,charSequence为encode返回的字符串 19 | // str字符串为数据库中密码字段返回的值 20 | String encodeStr = charSequence.toString() + "aa"; 21 | if (encodeStr.equals(str)) { 22 | return true; 23 | } 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Chapter2/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter2/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter2/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter2/restserver/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter2/restserver/src/main/java/net/anumbrella/rest/server/Application.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.rest.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author anumbrella 8 | */ 9 | @SpringBootApplication 10 | public class Application { 11 | public static void main(String[] args) { 12 | SpringApplication.run(Application.class, args); 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /Chapter2/restserver/src/main/java/net/anumbrella/rest/server/util/Base64Utils.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.rest.server.util; 2 | 3 | 4 | import java.util.Base64; 5 | 6 | /** 7 | * @author anumbrella 8 | */ 9 | public class Base64Utils { 10 | 11 | 12 | /** 13 | * 转换为base64 14 | * 15 | * @param msg 16 | * @return 17 | */ 18 | public static String encoder(String msg) { 19 | return Base64.getEncoder().encodeToString(msg.getBytes()); 20 | } 21 | 22 | /** 23 | * 解码base64 24 | * 25 | * @param msg 26 | * @return 27 | */ 28 | public static String decoder(String msg) { 29 | return new String(Base64.getDecoder().decode(msg)); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Chapter2/restserver/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8088 -------------------------------------------------------------------------------- /Chapter3/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(四)——[自定义认证登录策略](https://blog.csdn.net/Anumbrella/article/details/81590595). -------------------------------------------------------------------------------- /Chapter3/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter3/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter3/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter3/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private int expired; 13 | 14 | private int disabled; 15 | 16 | public String getUsername() { 17 | return username; 18 | } 19 | 20 | public void setUsername(String username) { 21 | this.username = username; 22 | } 23 | 24 | public String getPassword() { 25 | return password; 26 | } 27 | 28 | public void setPassword(String password) { 29 | this.password = password; 30 | } 31 | 32 | public int getExpired() { 33 | return expired; 34 | } 35 | 36 | public void setExpired(int expired) { 37 | this.expired = expired; 38 | } 39 | 40 | public int getDisabled() { 41 | return disabled; 42 | } 43 | 44 | public void setDisabled(int disabled) { 45 | this.disabled = disabled; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Chapter3/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=net.anumbrella.sso.config.CustomAuthenticationConfiguration -------------------------------------------------------------------------------- /Chapter3/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter3/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter3/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter4/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(五)——[Service配置及管理](https://blog.csdn.net/Anumbrella/article/details/82119246). 7 | -------------------------------------------------------------------------------- /Chapter4/cas-management-overlay/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | !/.project 3 | .project 4 | .settings 5 | target/ 6 | .idea/ 7 | .DS_Store 8 | .idea 9 | overlays/ 10 | .gradle/ 11 | build/ 12 | bin/ 13 | *.iml 14 | 15 | *.log.gz 16 | *.log -------------------------------------------------------------------------------- /Chapter4/cas-management-overlay/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function copy() { 5 | echo -e "Creating configuration directory under /etc/cas" 6 | mkdir -p /etc/cas/config 7 | 8 | echo -e "Copying configuration files from etc/cas to /etc/cas" 9 | cp -rfv etc/cas/* /etc/cas 10 | } 11 | 12 | function help() { 13 | echo "Usage: build.sh [copy|clean|package|run]" 14 | } 15 | 16 | function clean() { 17 | rm -Rf *.log 18 | rm -Rf *.log.gz 19 | ./mvnw clean "$@" 20 | } 21 | 22 | function package() { 23 | ./mvnw clean package -T 5 "$@" 24 | # copy 25 | } 26 | 27 | 28 | function run() { 29 | package && java -Xdebug -Xrunjdwp:transport=dt_socket,address=5000,server=y,suspend=n -jar target/cas-management.war 30 | } 31 | 32 | if [ $# -eq 0 ]; then 33 | echo -e "No commands provided. Defaulting to [run]\n" 34 | run 35 | exit 0 36 | fi 37 | 38 | 39 | case "$1" in 40 | "copy") 41 | copy 42 | ;; 43 | "clean") 44 | shift 45 | clean "$@" 46 | ;; 47 | "package") 48 | shift 49 | package "$@" 50 | ;; 51 | "run") 52 | run "$@" 53 | ;; 54 | *) 55 | help 56 | ;; 57 | esac 58 | 59 | -------------------------------------------------------------------------------- /Chapter4/cas-management-overlay/etc/cas/config/management.properties: -------------------------------------------------------------------------------- 1 | # CAS server that management app will authenticate with 2 | # This server will authenticate for any app (service) and you can login as casuser/Mellon 3 | cas.server.name: https://jasigcas.herokuapp.com 4 | cas.server.prefix: https://jasigcas.herokuapp.com/cas 5 | 6 | cas.mgmt.adminRoles[0]=ROLE_ADMIN 7 | cas.mgmt.userPropertiesFile=file:/etc/cas/config/users.properties 8 | 9 | # Update this URL to point at server running this management app 10 | cas.mgmt.serverName=https://mmoayyed.unicon.net:8443 11 | 12 | server.context-path=/cas-management 13 | server.port=8443 14 | 15 | logging.config=file:/etc/cas/config/log4j2-management.xml 16 | -------------------------------------------------------------------------------- /Chapter4/cas-management-overlay/etc/cas/config/users.properties: -------------------------------------------------------------------------------- 1 | # Only 'casuser' is authorized to use cas services management app 2 | casuser=notused,ROLE_ADMIN 3 | -------------------------------------------------------------------------------- /Chapter4/cas-management-overlay/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:36:18 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter4/cas-management-overlay/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter4/cas-management-overlay/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter4/cas-management-overlay/src/main/resources/user-details.properties: -------------------------------------------------------------------------------- 1 | casuser=notused,ROLE_ADMIN 2 | anumbrella=notused,ROLE_ADMIN -------------------------------------------------------------------------------- /Chapter4/cas-sample-java-webapp/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | !/.project 3 | .project 4 | .settings 5 | target/ 6 | .idea/ 7 | .DS_Store 8 | .idea 9 | overlays/ 10 | *.iml 11 | 12 | -------------------------------------------------------------------------------- /Chapter4/cas-sample-java-webapp/etc/jetty/jetty-https.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | http/1.1 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Chapter4/cas-sample-java-webapp/etc/jetty/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Chapter4/cas-sample-java-webapp/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Chapter4/cas-sample-java-webapp/src/main/webapp/logout.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html" %> 2 | <%@page pageEncoding="UTF-8" %> 3 | <%@ page import="java.util.Map" %> 4 | <%@ page import="java.util.Iterator" %> 5 | <%@ page import="org.jasig.cas.client.authentication.AttributePrincipal" %> 6 | 7 | 9 | 10 | <% 11 | session.invalidate(); 12 | %> 13 | 14 | 15 | 16 | 17 | CAS Example Java Web App 18 | 19 | 20 |

CAS Example Java Web App

21 |

Application session is now invalidated. You may also issue a request to "/cas/logout" to destroy the CAS SSO Session as well.

22 |
23 | 24 | Back to Home 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter4/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter4/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter4/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter4/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private int expired; 13 | 14 | private int disabled; 15 | 16 | public String getUsername() { 17 | return username; 18 | } 19 | 20 | public void setUsername(String username) { 21 | this.username = username; 22 | } 23 | 24 | public String getPassword() { 25 | return password; 26 | } 27 | 28 | public void setPassword(String password) { 29 | this.password = password; 30 | } 31 | 32 | public int getExpired() { 33 | return expired; 34 | } 35 | 36 | public void setExpired(int expired) { 37 | this.expired = expired; 38 | } 39 | 40 | public int getDisabled() { 41 | return disabled; 42 | } 43 | 44 | public void setDisabled(int disabled) { 45 | this.disabled = disabled; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Chapter4/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.anumbrella.sso.config.CustomAuthenticationConfiguration,\ 3 | net.anumbrella.sso.controller.ServicesManagerController -------------------------------------------------------------------------------- /Chapter4/cas-server/src/main/resources/services/web-10000001.json: -------------------------------------------------------------------------------- 1 | { 2 | "@class" : "org.apereo.cas.services.RegexRegisteredService", 3 | "serviceId" : "^(https|imaps|http)://.*", 4 | "name" : "web", 5 | "id" : 10000001, 6 | "evaluationOrder" : 10, 7 | "accessStrategy" : { 8 | "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", 9 | "enabled" : true, 10 | "ssoEnabled" : true 11 | } 12 | } -------------------------------------------------------------------------------- /Chapter4/cas-server/src/main/resources/services/web-10000001.yml: -------------------------------------------------------------------------------- 1 | --- ! 2 | serviceId: "^(https|imaps|http)://.*" 3 | name: "web" 4 | id: 10000001 5 | description: "description" 6 | evaluationOrder: 10 7 | attributeReleasePolicy: ! {} 8 | accessStrategy: ! 9 | enabled: true 10 | ssoEnabled: true -------------------------------------------------------------------------------- /Chapter4/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter4/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter4/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter5/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(六)——[自定义登录界面和表单信息](https://blog.csdn.net/Anumbrella/article/details/82728641). -------------------------------------------------------------------------------- /Chapter5/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter5/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter5/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter5/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private int expired; 13 | 14 | private int disabled; 15 | 16 | public String getUsername() { 17 | return username; 18 | } 19 | 20 | public void setUsername(String username) { 21 | this.username = username; 22 | } 23 | 24 | public String getPassword() { 25 | return password; 26 | } 27 | 28 | public void setPassword(String password) { 29 | this.password = password; 30 | } 31 | 32 | public int getExpired() { 33 | return expired; 34 | } 35 | 36 | public void setExpired(int expired) { 37 | this.expired = expired; 38 | } 39 | 40 | public int getDisabled() { 41 | return disabled; 42 | } 43 | 44 | public void setDisabled(int disabled) { 45 | this.disabled = disabled; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Chapter5/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.anumbrella.sso.config.CustomAuthenticationConfiguration,\ 3 | net.anumbrella.sso.controller.ServicesManagerController,\ 4 | net.anumbrella.sso.config.CustomerAuthWebflowConfiguration -------------------------------------------------------------------------------- /Chapter5/cas-server/src/main/resources/anumbrella.properties: -------------------------------------------------------------------------------- 1 | anumbrella.javascript.file=/themes/anumbrella/js/cas.js 2 | anumbrella.standard.css.file=/themes/anumbrella/css/cas.css 3 | 4 | anumbrella.login.images.path=/themes/anumbrella/images 5 | 6 | cas.standard.css.file=/css/cas.css 7 | cas.javascript.file=/js/cas.js 8 | cas.admin.css.file=/css/admin.css 9 | 10 | spring.thymeleaf.cache=false -------------------------------------------------------------------------------- /Chapter5/cas-server/src/main/resources/services/web-10000001.json: -------------------------------------------------------------------------------- 1 | { 2 | "@class" : "org.apereo.cas.services.RegexRegisteredService", 3 | "serviceId" : "^(https|imaps|http)://.*", 4 | "name" : "web", 5 | "id" : 10000001, 6 | "evaluationOrder" : 10, 7 | "accessStrategy" : { 8 | "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", 9 | "enabled" : true, 10 | "ssoEnabled" : true 11 | }, 12 | "theme": "anumbrella" 13 | } -------------------------------------------------------------------------------- /Chapter5/cas-server/src/main/resources/services/web-10000001.yml: -------------------------------------------------------------------------------- 1 | --- ! 2 | serviceId: "^(https|imaps|http)://.*" 3 | name: "web" 4 | id: 10000001 5 | description: "description" 6 | evaluationOrder: 10 7 | attributeReleasePolicy: ! {} 8 | accessStrategy: ! 9 | enabled: true 10 | ssoEnabled: true -------------------------------------------------------------------------------- /Chapter5/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter5/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter5/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg -------------------------------------------------------------------------------- /Chapter5/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter5/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter6/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(七)——[自定义验证码以及自定义错误信息](https://blog.csdn.net/Anumbrella/article/details/83154397). -------------------------------------------------------------------------------- /Chapter6/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter6/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter6/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/java/net/anumbrella/sso/config/CustomControllerConfigurer.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.config; 2 | 3 | 4 | import net.anumbrella.sso.controller.CaptchaController; 5 | import net.anumbrella.sso.controller.ServicesManagerController; 6 | import org.apereo.cas.configuration.CasConfigurationProperties; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 8 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | /** 13 | * @author anumbrella 14 | */ 15 | @Configuration("captchaConfiguration") 16 | @EnableConfigurationProperties(CasConfigurationProperties.class) 17 | public class CustomControllerConfigurer { 18 | 19 | /** 20 | * 验证码配置,注入bean到spring中 21 | * 22 | * @return 23 | */ 24 | @Bean 25 | @ConditionalOnMissingBean(name = "captchaController") 26 | public CaptchaController captchaController() { 27 | return new CaptchaController(); 28 | } 29 | 30 | 31 | /** 32 | * 自定义SercicesManage管理配置,注入bean到spring中 33 | * 34 | * @return 35 | */ 36 | @Bean 37 | @ConditionalOnMissingBean(name = "servicesManagerController") 38 | public ServicesManagerController servicesManagerController() { 39 | return new ServicesManagerController(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private int expired; 13 | 14 | private int disabled; 15 | 16 | public String getUsername() { 17 | return username; 18 | } 19 | 20 | public void setUsername(String username) { 21 | this.username = username; 22 | } 23 | 24 | public String getPassword() { 25 | return password; 26 | } 27 | 28 | public void setPassword(String password) { 29 | this.password = password; 30 | } 31 | 32 | public int getExpired() { 33 | return expired; 34 | } 35 | 36 | public void setExpired(int expired) { 37 | this.expired = expired; 38 | } 39 | 40 | public int getDisabled() { 41 | return disabled; 42 | } 43 | 44 | public void setDisabled(int disabled) { 45 | this.disabled = disabled; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/java/net/anumbrella/sso/exection/CheckCodeErrorException.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.exection; 2 | 3 | import org.apereo.cas.authentication.AuthenticationException; 4 | 5 | /** 6 | * @author Anumbrella 7 | */ 8 | public class CheckCodeErrorException extends AuthenticationException { 9 | 10 | 11 | public CheckCodeErrorException(){ 12 | super(); 13 | } 14 | 15 | 16 | public CheckCodeErrorException(String msg) { 17 | super(msg); 18 | } 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.anumbrella.sso.config.CustomAuthenticationConfiguration,\ 3 | net.anumbrella.sso.config.CustomerAuthWebflowConfiguration,\ 4 | net.anumbrella.sso.config.CustomControllerConfigurer -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/resources/anumbrella.properties: -------------------------------------------------------------------------------- 1 | anumbrella.javascript.file=/themes/anumbrella/js/cas.js 2 | anumbrella.standard.css.file=/themes/anumbrella/css/cas.css 3 | anumbrella.javascript.code.file=/themes/anumbrella/js/code.js 4 | 5 | anumbrella.login.images.path=/themes/anumbrella/images 6 | 7 | cas.standard.css.file=/css/cas.css 8 | cas.javascript.file=/js/cas.js 9 | cas.admin.css.file=/css/admin.css 10 | 11 | spring.thymeleaf.cache=false -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/resources/services/web-10000001.json: -------------------------------------------------------------------------------- 1 | { 2 | "@class" : "org.apereo.cas.services.RegexRegisteredService", 3 | "serviceId" : "^(https|imaps|http)://.*", 4 | "name" : "web", 5 | "id" : 10000001, 6 | "evaluationOrder" : 10, 7 | "accessStrategy" : { 8 | "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", 9 | "enabled" : true, 10 | "ssoEnabled" : true 11 | }, 12 | "theme": "anumbrella" 13 | } -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/resources/services/web-10000001.yml: -------------------------------------------------------------------------------- 1 | --- ! 2 | serviceId: "^(https|imaps|http)://.*" 3 | name: "web" 4 | id: 10000001 5 | description: "description" 6 | evaluationOrder: 10 7 | attributeReleasePolicy: ! {} 8 | accessStrategy: ! 9 | enabled: true 10 | ssoEnabled: true -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter6/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/resources/static/themes/anumbrella/js/code.js: -------------------------------------------------------------------------------- 1 | function changeCode(){ 2 | var node = document.getElementById("captcha_img"); 3 | //修改验证码 4 | if (node){ 5 | if(url.indexOf("?") >= 0){ 6 | node.src = url.split('?')[0] +'?id='+uuid(); 7 | }else{ 8 | node.src = url +'?id='+uuid(); 9 | } 10 | } 11 | } 12 | 13 | 14 | function uuid(){ 15 | //获取系统当前的时间 16 | var d = new Date().getTime(); 17 | //替换uuid里面的x和y 18 | var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 19 | //取余 16进制 20 | var r = (d + Math.random()*16)%16 | 0; 21 | //向下去整 22 | d = Math.floor(d/16); 23 | //toString 表示编程16进制的数据 24 | return (c=='x' ? r : (r&0x3|0x8)).toString(16); 25 | }); 26 | return uuid; 27 | }; 28 | -------------------------------------------------------------------------------- /Chapter6/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter6/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter7/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(八)——[多属性返回](https://blog.csdn.net/Anumbrella/article/details/85132517). -------------------------------------------------------------------------------- /Chapter7/cas-management-overlay/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | !/.project 3 | .project 4 | .settings 5 | target/ 6 | .idea/ 7 | .DS_Store 8 | .idea 9 | overlays/ 10 | .gradle/ 11 | build/ 12 | bin/ 13 | *.iml 14 | 15 | *.log.gz 16 | *.log -------------------------------------------------------------------------------- /Chapter7/cas-management-overlay/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function copy() { 5 | echo -e "Creating configuration directory under /etc/cas" 6 | mkdir -p /etc/cas/config 7 | 8 | echo -e "Copying configuration files from etc/cas to /etc/cas" 9 | cp -rfv etc/cas/* /etc/cas 10 | } 11 | 12 | function help() { 13 | echo "Usage: build.sh [copy|clean|package|run]" 14 | } 15 | 16 | function clean() { 17 | rm -Rf *.log 18 | rm -Rf *.log.gz 19 | ./mvnw clean "$@" 20 | } 21 | 22 | function package() { 23 | ./mvnw clean package -T 5 "$@" 24 | # copy 25 | } 26 | 27 | 28 | function run() { 29 | package && java -Xdebug -Xrunjdwp:transport=dt_socket,address=5000,server=y,suspend=n -jar target/cas-management.war 30 | } 31 | 32 | if [ $# -eq 0 ]; then 33 | echo -e "No commands provided. Defaulting to [run]\n" 34 | run 35 | exit 0 36 | fi 37 | 38 | 39 | case "$1" in 40 | "copy") 41 | copy 42 | ;; 43 | "clean") 44 | shift 45 | clean "$@" 46 | ;; 47 | "package") 48 | shift 49 | package "$@" 50 | ;; 51 | "run") 52 | run "$@" 53 | ;; 54 | *) 55 | help 56 | ;; 57 | esac 58 | 59 | -------------------------------------------------------------------------------- /Chapter7/cas-management-overlay/etc/cas/config/management.properties: -------------------------------------------------------------------------------- 1 | # CAS server that management app will authenticate with 2 | # This server will authenticate for any app (service) and you can login as casuser/Mellon 3 | cas.server.name: https://jasigcas.herokuapp.com 4 | cas.server.prefix: https://jasigcas.herokuapp.com/cas 5 | 6 | cas.mgmt.adminRoles[0]=ROLE_ADMIN 7 | cas.mgmt.userPropertiesFile=file:/etc/cas/config/users.properties 8 | 9 | # Update this URL to point at server running this management app 10 | cas.mgmt.serverName=https://mmoayyed.unicon.net:8443 11 | 12 | server.context-path=/cas-management 13 | server.port=8443 14 | 15 | logging.config=file:/etc/cas/config/log4j2-management.xml 16 | -------------------------------------------------------------------------------- /Chapter7/cas-management-overlay/etc/cas/config/users.properties: -------------------------------------------------------------------------------- 1 | # Only 'casuser' is authorized to use cas services management app 2 | casuser=notused,ROLE_ADMIN 3 | -------------------------------------------------------------------------------- /Chapter7/cas-management-overlay/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:36:18 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter7/cas-management-overlay/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter7/cas-management-overlay/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter7/cas-management-overlay/src/main/resources/user-details.properties: -------------------------------------------------------------------------------- 1 | casuser=notused,ROLE_ADMIN 2 | anumbrella=notused,ROLE_ADMIN -------------------------------------------------------------------------------- /Chapter7/cas-sample-java-webapp/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | !/.project 3 | .project 4 | .settings 5 | target/ 6 | .idea/ 7 | .DS_Store 8 | .idea 9 | overlays/ 10 | *.iml 11 | 12 | -------------------------------------------------------------------------------- /Chapter7/cas-sample-java-webapp/etc/jetty/jetty-https.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | http/1.1 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Chapter7/cas-sample-java-webapp/etc/jetty/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Chapter7/cas-sample-java-webapp/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Chapter7/cas-sample-java-webapp/src/main/webapp/logout.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html" %> 2 | <%@page pageEncoding="UTF-8" %> 3 | <%@ page import="java.util.Map" %> 4 | <%@ page import="java.util.Iterator" %> 5 | <%@ page import="org.jasig.cas.client.authentication.AttributePrincipal" %> 6 | 7 | 9 | 10 | <% 11 | session.invalidate(); 12 | %> 13 | 14 | 15 | 16 | 17 | CAS Example Java Web App 18 | 19 | 20 |

CAS Example Java Web App

21 |

Application session is now invalidated. You may also issue a request to "/cas/logout" to destroy the CAS SSO Session as well.

22 |
23 | 24 | Back to Home 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter7/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter7/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter7/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/java/net/anumbrella/sso/config/CustomControllerConfigurer.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.config; 2 | 3 | 4 | import net.anumbrella.sso.controller.CaptchaController; 5 | import net.anumbrella.sso.controller.ServicesManagerController; 6 | import org.apereo.cas.configuration.CasConfigurationProperties; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 8 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | /** 13 | * @author anumbrella 14 | */ 15 | @Configuration("captchaConfiguration") 16 | @EnableConfigurationProperties(CasConfigurationProperties.class) 17 | public class CustomControllerConfigurer { 18 | 19 | /** 20 | * 验证码配置,注入bean到spring中 21 | * 22 | * @return 23 | */ 24 | @Bean 25 | @ConditionalOnMissingBean(name = "captchaController") 26 | public CaptchaController captchaController() { 27 | return new CaptchaController(); 28 | } 29 | 30 | 31 | /** 32 | * 自定义SercicesManage管理配置,注入bean到spring中 33 | * 34 | * @return 35 | */ 36 | @Bean 37 | @ConditionalOnMissingBean(name = "servicesManagerController") 38 | public ServicesManagerController servicesManagerController() { 39 | return new ServicesManagerController(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private String email; 13 | 14 | private int expired; 15 | 16 | private int disabled; 17 | 18 | public String getUsername() { 19 | return username; 20 | } 21 | 22 | public void setUsername(String username) { 23 | this.username = username; 24 | } 25 | 26 | public String getPassword() { 27 | return password; 28 | } 29 | 30 | public void setPassword(String password) { 31 | this.password = password; 32 | } 33 | 34 | public int getExpired() { 35 | return expired; 36 | } 37 | 38 | public void setExpired(int expired) { 39 | this.expired = expired; 40 | } 41 | 42 | public int getDisabled() { 43 | return disabled; 44 | } 45 | 46 | public void setDisabled(int disabled) { 47 | this.disabled = disabled; 48 | } 49 | 50 | public String getEmail() { 51 | return email; 52 | } 53 | 54 | public void setEmail(String email) { 55 | this.email = email; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/java/net/anumbrella/sso/exection/CheckCodeErrorException.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.exection; 2 | 3 | import org.apereo.cas.authentication.AuthenticationException; 4 | 5 | /** 6 | * @author Anumbrella 7 | */ 8 | public class CheckCodeErrorException extends AuthenticationException { 9 | 10 | 11 | public CheckCodeErrorException(){ 12 | super(); 13 | } 14 | 15 | 16 | public CheckCodeErrorException(String msg) { 17 | super(msg); 18 | } 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.anumbrella.sso.config.CustomAuthenticationConfiguration,\ 3 | net.anumbrella.sso.config.CustomerAuthWebflowConfiguration,\ 4 | net.anumbrella.sso.config.CustomControllerConfigurer -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/resources/anumbrella.properties: -------------------------------------------------------------------------------- 1 | anumbrella.javascript.file=/themes/anumbrella/js/cas.js 2 | anumbrella.standard.css.file=/themes/anumbrella/css/cas.css 3 | anumbrella.javascript.code.file=/themes/anumbrella/js/code.js 4 | 5 | anumbrella.login.images.path=/themes/anumbrella/images 6 | 7 | cas.standard.css.file=/css/cas.css 8 | cas.javascript.file=/js/cas.js 9 | cas.admin.css.file=/css/admin.css 10 | 11 | spring.thymeleaf.cache=false -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/resources/services/web-10000001.json: -------------------------------------------------------------------------------- 1 | { 2 | "@class" : "org.apereo.cas.services.RegexRegisteredService", 3 | "serviceId" : "^(https|imaps|http)://.*", 4 | "name" : "web", 5 | "id" : 10000001, 6 | "evaluationOrder" : 10, 7 | "accessStrategy" : { 8 | "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", 9 | "enabled" : true, 10 | "ssoEnabled" : true 11 | }, 12 | "attributeReleasePolicy": { 13 | "@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy" 14 | }, 15 | "theme": "anumbrella" 16 | } -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/resources/services/web-10000001.yml: -------------------------------------------------------------------------------- 1 | --- ! 2 | serviceId: "^(https|imaps|http)://.*" 3 | name: "web" 4 | id: 10000001 5 | description: "description" 6 | evaluationOrder: 10 7 | attributeReleasePolicy: ! {} 8 | accessStrategy: ! 9 | enabled: true 10 | ssoEnabled: true -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter7/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/resources/static/themes/anumbrella/js/code.js: -------------------------------------------------------------------------------- 1 | function changeCode(){ 2 | var node = document.getElementById("captcha_img"); 3 | var url = node.src; 4 | // 修改验证码 5 | if (node){ 6 | if(url.indexOf("?") >= 0){ 7 | node.src = url.split('?')[0] +'?id='+uuid(); 8 | }else{ 9 | node.src = url +'?id='+uuid(); 10 | } 11 | 12 | } 13 | } 14 | 15 | 16 | function uuid(){ 17 | //获取系统当前的时间 18 | var d = new Date().getTime(); 19 | //替换uuid里面的x和y 20 | var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 21 | //取余 16进制 22 | var r = (d + Math.random()*16)%16 | 0; 23 | //向下去整 24 | d = Math.floor(d/16); 25 | //toString 表示编程16进制的数据 26 | return (c=='x' ? r : (r&0x3|0x8)).toString(16); 27 | }); 28 | return uuid; 29 | }; -------------------------------------------------------------------------------- /Chapter7/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter7/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter7/restserver/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter7/restserver/src/main/java/net/anumbrella/rest/server/Application.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.rest.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author anumbrella 8 | */ 9 | @SpringBootApplication 10 | public class Application { 11 | public static void main(String[] args) { 12 | SpringApplication.run(Application.class, args); 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /Chapter7/restserver/src/main/java/net/anumbrella/rest/server/controller/RestAttributeController.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.rest.server.controller; 2 | 3 | 4 | import net.anumbrella.rest.server.entity.SysUser; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.http.HttpHeaders; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestHeader; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * @author anumbrella 17 | */ 18 | @RestController 19 | public class RestAttributeController { 20 | 21 | private static final Logger LOGGER = LoggerFactory.getLogger(RestAttributeController.class); 22 | 23 | 24 | @PostMapping("/attributes") 25 | public Object getAttributes(@RequestHeader HttpHeaders httpHeaders) { 26 | 27 | SysUser user = new SysUser(); 28 | 29 | user.setEmail("rest@gmail.com"); 30 | user.setUsername("email"); 31 | user.setPassword("123"); 32 | List role = new ArrayList<>(); 33 | role.add("admin"); 34 | role.add("dev"); 35 | user.setRole(role); 36 | //成功返回json 37 | return user; 38 | } 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Chapter7/restserver/src/main/java/net/anumbrella/rest/server/util/Base64Utils.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.rest.server.util; 2 | 3 | 4 | import java.util.Base64; 5 | 6 | /** 7 | * @author anumbrella 8 | */ 9 | public class Base64Utils { 10 | 11 | 12 | /** 13 | * 转换为base64 14 | * 15 | * @param msg 16 | * @return 17 | */ 18 | public static String encoder(String msg) { 19 | return Base64.getEncoder().encodeToString(msg.getBytes()); 20 | } 21 | 22 | /** 23 | * 解码base64 24 | * 25 | * @param msg 26 | * @return 27 | */ 28 | public static String decoder(String msg) { 29 | return new String(Base64.getDecoder().decode(msg)); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Chapter7/restserver/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8088 -------------------------------------------------------------------------------- /Chapter7/restserver/target/classes/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8088 -------------------------------------------------------------------------------- /Chapter8/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(九)——[客户端接入](https://blog.csdn.net/Anumbrella/article/details/87897230). -------------------------------------------------------------------------------- /Chapter8/cas-sample-java-webapp/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | !/.project 3 | .project 4 | .settings 5 | target/ 6 | .idea/ 7 | .DS_Store 8 | .idea 9 | overlays/ 10 | *.iml 11 | 12 | -------------------------------------------------------------------------------- /Chapter8/cas-sample-java-webapp/etc/jetty/jetty-https.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | http/1.1 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Chapter8/cas-sample-java-webapp/etc/jetty/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Chapter8/cas-sample-java-webapp/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Chapter8/cas-sample-java-webapp/src/main/webapp/logout.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html" %> 2 | <%@page pageEncoding="UTF-8" %> 3 | <%@ page import="java.util.Map" %> 4 | <%@ page import="java.util.Iterator" %> 5 | <%@ page import="org.jasig.cas.client.authentication.AttributePrincipal" %> 6 | 7 | 9 | 10 | <% 11 | session.invalidate(); 12 | %> 13 | 14 | 15 | 16 | 17 | CAS Example Java Web App 18 | 19 | 20 |

CAS Example Java Web App

21 |

Application session is now invalidated. You may also issue a request to "/cas/logout" to destroy the CAS SSO Session as well.

22 |
23 | 24 | Back to Home 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter8/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter8/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter8/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/java/net/anumbrella/sso/config/CustomControllerConfigurer.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.config; 2 | 3 | 4 | import net.anumbrella.sso.controller.CaptchaController; 5 | import net.anumbrella.sso.controller.ServicesManagerController; 6 | import org.apereo.cas.configuration.CasConfigurationProperties; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 8 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | /** 13 | * @author anumbrella 14 | */ 15 | @Configuration("captchaConfiguration") 16 | @EnableConfigurationProperties(CasConfigurationProperties.class) 17 | public class CustomControllerConfigurer { 18 | 19 | /** 20 | * 验证码配置,注入bean到spring中 21 | * 22 | * @return 23 | */ 24 | @Bean 25 | @ConditionalOnMissingBean(name = "captchaController") 26 | public CaptchaController captchaController() { 27 | return new CaptchaController(); 28 | } 29 | 30 | 31 | /** 32 | * 自定义SercicesManage管理配置,注入bean到spring中 33 | * 34 | * @return 35 | */ 36 | @Bean 37 | @ConditionalOnMissingBean(name = "servicesManagerController") 38 | public ServicesManagerController servicesManagerController() { 39 | return new ServicesManagerController(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private String email; 13 | 14 | private int expired; 15 | 16 | private int disabled; 17 | 18 | public String getUsername() { 19 | return username; 20 | } 21 | 22 | public void setUsername(String username) { 23 | this.username = username; 24 | } 25 | 26 | public String getPassword() { 27 | return password; 28 | } 29 | 30 | public void setPassword(String password) { 31 | this.password = password; 32 | } 33 | 34 | public int getExpired() { 35 | return expired; 36 | } 37 | 38 | public void setExpired(int expired) { 39 | this.expired = expired; 40 | } 41 | 42 | public int getDisabled() { 43 | return disabled; 44 | } 45 | 46 | public void setDisabled(int disabled) { 47 | this.disabled = disabled; 48 | } 49 | 50 | public String getEmail() { 51 | return email; 52 | } 53 | 54 | public void setEmail(String email) { 55 | this.email = email; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/java/net/anumbrella/sso/exection/CheckCodeErrorException.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.exection; 2 | 3 | import org.apereo.cas.authentication.AuthenticationException; 4 | 5 | /** 6 | * @author Anumbrella 7 | */ 8 | public class CheckCodeErrorException extends AuthenticationException { 9 | 10 | 11 | public CheckCodeErrorException(){ 12 | super(); 13 | } 14 | 15 | 16 | public CheckCodeErrorException(String msg) { 17 | super(msg); 18 | } 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.anumbrella.sso.config.CustomAuthenticationConfiguration,\ 3 | net.anumbrella.sso.config.CustomerAuthWebflowConfiguration,\ 4 | net.anumbrella.sso.config.CustomControllerConfigurer -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/resources/anumbrella.properties: -------------------------------------------------------------------------------- 1 | anumbrella.javascript.file=/themes/anumbrella/js/cas.js 2 | anumbrella.standard.css.file=/themes/anumbrella/css/cas.css 3 | anumbrella.javascript.code.file=/themes/anumbrella/js/code.js 4 | 5 | anumbrella.login.images.path=/themes/anumbrella/images 6 | 7 | cas.standard.css.file=/css/cas.css 8 | cas.javascript.file=/js/cas.js 9 | cas.admin.css.file=/css/admin.css 10 | 11 | spring.thymeleaf.cache=false -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/resources/services/web-10000001.json: -------------------------------------------------------------------------------- 1 | { 2 | "@class" : "org.apereo.cas.services.RegexRegisteredService", 3 | "serviceId" : "^(https|imaps|http)://.*", 4 | "name" : "web", 5 | "id" : 10000001, 6 | "evaluationOrder" : 10, 7 | "accessStrategy" : { 8 | "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", 9 | "enabled" : true, 10 | "ssoEnabled" : true 11 | }, 12 | "attributeReleasePolicy": { 13 | "@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy" 14 | }, 15 | "theme": "anumbrella" 16 | } -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/resources/services/web-10000001.yml: -------------------------------------------------------------------------------- 1 | --- ! 2 | serviceId: "^(https|imaps|http)://.*" 3 | name: "web" 4 | id: 10000001 5 | description: "description" 6 | evaluationOrder: 10 7 | attributeReleasePolicy: ! {} 8 | accessStrategy: ! 9 | enabled: true 10 | ssoEnabled: true -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter8/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/resources/static/themes/anumbrella/js/code.js: -------------------------------------------------------------------------------- 1 | function changeCode(){ 2 | var node = document.getElementById("captcha_img"); 3 | var url = node.src; 4 | // 修改验证码 5 | if (node){ 6 | if(url.indexOf("?") >= 0){ 7 | node.src = url.split('?')[0] +'?id='+uuid(); 8 | }else{ 9 | node.src = url +'?id='+uuid(); 10 | } 11 | 12 | } 13 | } 14 | 15 | 16 | function uuid(){ 17 | //获取系统当前的时间 18 | var d = new Date().getTime(); 19 | //替换uuid里面的x和y 20 | var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 21 | //取余 16进制 22 | var r = (d + Math.random()*16)%16 | 0; 23 | //向下去整 24 | d = Math.floor(d/16); 25 | //toString 表示编程16进制的数据 26 | return (c=='x' ? r : (r&0x3|0x8)).toString(16); 27 | }); 28 | return uuid; 29 | }; -------------------------------------------------------------------------------- /Chapter8/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter8/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /Chapter8/client-demo/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter8/client-demo/src/main/java/net/anumbrella/sso/Application.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Chapter8/client-demo/src/main/java/net/anumbrella/sso/dao/LoginDao.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.dao; 2 | 3 | 4 | import net.anumbrella.sso.entity.User; 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author Anumbrella 12 | */ 13 | @Repository 14 | public interface LoginDao extends CrudRepository { 15 | 16 | List findByUsernameAndPassword(String name, String password); 17 | } -------------------------------------------------------------------------------- /Chapter8/client-demo/src/main/java/net/anumbrella/sso/service/LoginService.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.service; 2 | 3 | 4 | import net.anumbrella.sso.dao.LoginDao; 5 | import net.anumbrella.sso.entity.User; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author Anumbrella 13 | */ 14 | @Service 15 | public class LoginService { 16 | 17 | @Autowired 18 | private LoginDao loginDao; 19 | 20 | public boolean verifyLogin(User user) { 21 | 22 | List userList = loginDao.findByUsernameAndPassword(user.getUsername(), user.getPassword()); 23 | return userList.size() > 0; 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /Chapter8/client-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://localhost:3306/cas?characterEncoding=UTF-8&useUnicode=true 2 | spring.datasource.username=root 3 | spring.datasource.password=123 4 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 5 | spring.jpa.properties.hibernate.hbm2ddl.auto=update 6 | 7 | server.port=9443 8 | #你生成的证书名字 9 | server.ssl.key-store=/Users/anumbrella/keystore/thekeystore2 10 | #密钥库密码 11 | server.ssl.key-store-password=123456 12 | server.ssl.keyStoreType=JKS 13 | 14 | 15 | # 监听退出的接口,即所有接口都会进行监听 16 | spring.cas.sign-out-filters=/* 17 | # 需要拦截的认证的接口 18 | spring.cas.auth-filters=/* 19 | spring.cas.validate-filters=/* 20 | spring.cas.request-wrapper-filters=/* 21 | spring.cas.assertion-filters=/* 22 | # 表示忽略拦截的接口,也就是不用进行拦截 23 | spring.cas.ignore-filters=/test 24 | spring.cas.cas-server-login-url=https://sso.anumbrella.net:8443/cas/login 25 | spring.cas.cas-server-url-prefix=https://sso.anumbrella.net:8443/cas/ 26 | spring.cas.redirect-after-validation=true 27 | spring.cas.use-session=true 28 | spring.cas.server-name=https://client.anumbrella.net:9443 29 | -------------------------------------------------------------------------------- /Chapter8/client-demo/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 你好! 9 |
10 | 注销 11 | 12 | -------------------------------------------------------------------------------- /Chapter8/client-demo/src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | cas登录 7 | 12 | 13 | 14 |
15 |
16 |
    17 |
  • 18 | 19 |
    20 | 21 |
    22 |
  • 23 |
  • 24 | 25 |
    26 | 27 |
    28 |
  • 29 |
  • 30 |
    31 | 32 |
    33 |
  • 34 |
35 |
36 |
37 | 38 | -------------------------------------------------------------------------------- /Chapter9/README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | CAS单点登录 demo 4 | 5 | 6 | ## CAS单点登录(十)——[通过Restful协议请求认证和退出](https://blog.csdn.net/Anumbrella/article/details/88912964). -------------------------------------------------------------------------------- /Chapter9/cas-sample-java-webapp/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | !/.project 3 | .project 4 | .settings 5 | target/ 6 | .idea/ 7 | .DS_Store 8 | .idea 9 | overlays/ 10 | *.iml 11 | 12 | -------------------------------------------------------------------------------- /Chapter9/cas-sample-java-webapp/etc/jetty/jetty-https.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | http/1.1 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Chapter9/cas-sample-java-webapp/etc/jetty/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Chapter9/cas-sample-java-webapp/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Chapter9/cas-sample-java-webapp/src/main/webapp/logout.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html" %> 2 | <%@page pageEncoding="UTF-8" %> 3 | <%@ page import="java.util.Map" %> 4 | <%@ page import="java.util.Iterator" %> 5 | <%@ page import="org.jasig.cas.client.authentication.AttributePrincipal" %> 6 | 7 | 9 | 10 | <% 11 | session.invalidate(); 12 | %> 13 | 14 | 15 | 16 | 17 | CAS Example Java Web App 18 | 19 | 20 |

CAS Example Java Web App

21 |

Application session is now invalidated. You may also issue a request to "/cas/logout" to destroy the CAS SSO Session as well.

22 |
23 | 24 | Back to Home 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter9/cas-server/.gitignore: -------------------------------------------------------------------------------- 1 | overlays/* 2 | .DS_Store 3 | target/* 4 | *.iml -------------------------------------------------------------------------------- /Chapter9/cas-server/etc/cas/config/cas.properties: -------------------------------------------------------------------------------- 1 | cas.server.name: https://cas.example.org:8443 2 | cas.server.prefix: https://cas.example.org:8443/cas 3 | 4 | cas.adminPagesSecurity.ip=127\.0\.0\.1 5 | 6 | logging.config: file:/etc/cas/config/log4j2.xml 7 | -------------------------------------------------------------------------------- /Chapter9/cas-server/maven/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Maven download properties 2 | #Fri Dec 01 21:35:11 MST 2017 3 | distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 4 | -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/java/net/anumbrella/sso/config/CustomControllerConfigurer.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.config; 2 | 3 | 4 | import net.anumbrella.sso.controller.CaptchaController; 5 | import net.anumbrella.sso.controller.ServicesManagerController; 6 | import org.apereo.cas.configuration.CasConfigurationProperties; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 8 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | /** 13 | * @author anumbrella 14 | */ 15 | @Configuration("captchaConfiguration") 16 | @EnableConfigurationProperties(CasConfigurationProperties.class) 17 | public class CustomControllerConfigurer { 18 | 19 | /** 20 | * 验证码配置,注入bean到spring中 21 | * 22 | * @return 23 | */ 24 | @Bean 25 | @ConditionalOnMissingBean(name = "captchaController") 26 | public CaptchaController captchaController() { 27 | return new CaptchaController(); 28 | } 29 | 30 | 31 | /** 32 | * 自定义SercicesManage管理配置,注入bean到spring中 33 | * 34 | * @return 35 | */ 36 | @Bean 37 | @ConditionalOnMissingBean(name = "servicesManagerController") 38 | public ServicesManagerController servicesManagerController() { 39 | return new ServicesManagerController(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/java/net/anumbrella/sso/entity/User.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.entity; 2 | 3 | /** 4 | * @author anumbrella 5 | */ 6 | public class User { 7 | 8 | private String username; 9 | 10 | private String password; 11 | 12 | private String email; 13 | 14 | private int expired; 15 | 16 | private int disabled; 17 | 18 | public String getUsername() { 19 | return username; 20 | } 21 | 22 | public void setUsername(String username) { 23 | this.username = username; 24 | } 25 | 26 | public String getPassword() { 27 | return password; 28 | } 29 | 30 | public void setPassword(String password) { 31 | this.password = password; 32 | } 33 | 34 | public int getExpired() { 35 | return expired; 36 | } 37 | 38 | public void setExpired(int expired) { 39 | this.expired = expired; 40 | } 41 | 42 | public int getDisabled() { 43 | return disabled; 44 | } 45 | 46 | public void setDisabled(int disabled) { 47 | this.disabled = disabled; 48 | } 49 | 50 | public String getEmail() { 51 | return email; 52 | } 53 | 54 | public void setEmail(String email) { 55 | this.email = email; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/java/net/anumbrella/sso/exection/CheckCodeErrorException.java: -------------------------------------------------------------------------------- 1 | package net.anumbrella.sso.exection; 2 | 3 | import org.apereo.cas.authentication.AuthenticationException; 4 | 5 | /** 6 | * @author Anumbrella 7 | */ 8 | public class CheckCodeErrorException extends AuthenticationException { 9 | 10 | 11 | public CheckCodeErrorException(){ 12 | super(); 13 | } 14 | 15 | 16 | public CheckCodeErrorException(String msg) { 17 | super(msg); 18 | } 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.anumbrella.sso.config.CustomAuthenticationConfiguration,\ 3 | net.anumbrella.sso.config.CustomerAuthWebflowConfiguration,\ 4 | net.anumbrella.sso.config.CustomControllerConfigurer -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/resources/anumbrella.properties: -------------------------------------------------------------------------------- 1 | anumbrella.javascript.file=/themes/anumbrella/js/cas.js 2 | anumbrella.standard.css.file=/themes/anumbrella/css/cas.css 3 | anumbrella.javascript.code.file=/themes/anumbrella/js/code.js 4 | 5 | anumbrella.login.images.path=/themes/anumbrella/images 6 | 7 | cas.standard.css.file=/css/cas.css 8 | cas.javascript.file=/js/cas.js 9 | cas.admin.css.file=/css/admin.css 10 | 11 | spring.thymeleaf.cache=false -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/resources/services/web-10000001.json: -------------------------------------------------------------------------------- 1 | { 2 | "@class" : "org.apereo.cas.services.RegexRegisteredService", 3 | "serviceId" : "^(https|imaps|http)://.*", 4 | "name" : "web", 5 | "id" : 10000001, 6 | "evaluationOrder" : 10, 7 | "accessStrategy" : { 8 | "@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", 9 | "enabled" : true, 10 | "ssoEnabled" : true 11 | }, 12 | "attributeReleasePolicy": { 13 | "@class": "org.apereo.cas.services.ReturnAllAttributeReleasePolicy" 14 | }, 15 | "theme": "anumbrella" 16 | } -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/resources/services/web-10000001.yml: -------------------------------------------------------------------------------- 1 | --- ! 2 | serviceId: "^(https|imaps|http)://.*" 3 | name: "web" 4 | id: 10000001 5 | description: "description" 6 | evaluationOrder: 10 7 | attributeReleasePolicy: ! {} 8 | accessStrategy: ! 9 | enabled: true 10 | ssoEnabled: true -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager 3 | securityManager.cacheManager = $cacheManager 4 | 5 | [users] 6 | anumbrella=123, admin, developer 7 | test=test, developer 8 | 9 | [roles] 10 | admin = system,admin,staff,superuser:* 11 | developer = commit:* -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter9/cas-server/src/main/resources/static/themes/anumbrella/images/po.jpeg -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/resources/static/themes/anumbrella/js/code.js: -------------------------------------------------------------------------------- 1 | function changeCode(){ 2 | var node = document.getElementById("captcha_img"); 3 | var url = node.src; 4 | // 修改验证码 5 | if (node){ 6 | if(url.indexOf("?") >= 0){ 7 | node.src = url.split('?')[0] +'?id='+uuid(); 8 | }else{ 9 | node.src = url +'?id='+uuid(); 10 | } 11 | 12 | } 13 | } 14 | 15 | 16 | function uuid(){ 17 | //获取系统当前的时间 18 | var d = new Date().getTime(); 19 | //替换uuid里面的x和y 20 | var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 21 | //取余 16进制 22 | var r = (d + Math.random()*16)%16 | 0; 23 | //向下去整 24 | d = Math.floor(d/16); 25 | //toString 表示编程16进制的数据 26 | return (c=='x' ? r : (r&0x3|0x8)).toString(16); 27 | }); 28 | return uuid; 29 | }; -------------------------------------------------------------------------------- /Chapter9/cas-server/src/main/resources/thekeystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuyun123/CAS/7799f38e91584c49224d3be20d2c56c79301ec09/Chapter9/cas-server/src/main/resources/thekeystore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CAS 2 | 3 | 4 | CAS单点登录 demo 5 | 6 | 7 | ## 详细博文——[CAS单点登录学习](https://blog.csdn.net/anumbrella/article/category/7765386). --------------------------------------------------------------------------------