├── .gitignore ├── LICENSE ├── README.md ├── http └── civism-sso.http ├── pom.xml ├── sql └── sso.sql └── src ├── main ├── java │ └── com │ │ └── civism │ │ └── sso │ │ ├── SsoApplication.java │ │ ├── aop │ │ └── GlobalExceptionAop.java │ │ ├── config │ │ ├── RedisAutoConfiguration.java │ │ ├── ShiroConfig.java │ │ ├── ShiroFilterRegisterConfig.java │ │ └── SwaggerConfig.java │ │ ├── constant │ │ └── CivismConstant.java │ │ ├── controller │ │ └── IndexController.java │ │ ├── dao │ │ ├── SsoFunctionDao.java │ │ ├── SsoProductDao.java │ │ └── SsoUserDao.java │ │ ├── entity │ │ ├── AuthEntity.java │ │ ├── BaseDO.java │ │ ├── LoginEntity.java │ │ ├── Response.java │ │ ├── SsoFunctionDO.java │ │ ├── SsoProductDO.java │ │ ├── SsoUserDO.java │ │ └── UserInfo.java │ │ ├── enums │ │ └── CustomExceptionEnum.java │ │ ├── exception │ │ └── CustomException.java │ │ ├── filter │ │ ├── BaseCheckFilter.java │ │ ├── CheckLoginFilter.java │ │ └── RefreshFilter.java │ │ ├── redis │ │ └── RedisClient.java │ │ ├── service │ │ ├── SsoFunctionService.java │ │ ├── SsoProductService.java │ │ ├── SsoUserService.java │ │ └── impl │ │ │ ├── SsoFunctionServiceImpl.java │ │ │ ├── SsoProductServiceImpl.java │ │ │ └── SsoUserServiceImpl.java │ │ └── shiro │ │ ├── CivismShiroUpmsRealm.java │ │ ├── CustomRolePermissionResolver.java │ │ ├── JavaUuidSessionIdGenerator.java │ │ ├── RolePermission.java │ │ ├── ShiroRedisCacheSessionDAO.java │ │ ├── ShiroSessionManager.java │ │ ├── UrlPathMatcher.java │ │ ├── UrlPermission.java │ │ └── UrlPermissionResolver.java └── resources │ ├── application.yml │ └── mapper │ └── sso_product.xml └── test └── java └── com └── civism └── sso └── SsoApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.classpath 2 | *.project 3 | install.bat 4 | /target 5 | *.settings 6 | target 7 | .idea 8 | *.iml 9 | .svn 10 | node_modules 11 | *.ipr 12 | *.iws 13 | .DS_Store 14 | /logs 15 | logs 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 若需要springmvc版本,请切换到提交记录log:241cc8451ecef46e3b4467bd864c2768052f5123 3 | # 介绍 4 | civism-sso基于springmvc+redis+shiro 实现的分布式单点登录系统,继承了登录验证以及数据接口鉴权, 5 | 能很好的帮助其他项目做前后端分析,并且不需要其他子系统关心权限,并且该项目支持跨域请求 6 | # 功能介绍 7 | * sso登录:统一登录后,跳转任何子系统不需要再次登录 8 | * 鉴权:在子项目中,filter拦截所有数据请求转发到sso的/authorize路径,根据sso返回值来判断是否有权限访问 9 | * 跨域:sso支持不同域名的访问,采用了jsonp请求方式,返回可执行代码来达到跨域 10 | * 前后端分离:sso只有json接口返回,没有页面,跳转逻辑完全由前端控制,能更好的促进前后端分离开发 11 | # 操作步骤 12 | 1. 修改redis配置文件 13 | 2. 用jetty或tomcat启动civism-sso项目 14 | 3. 访问localhost:9999/login/index?userName=admin&password=123456&way=1&callback=hello获取token 15 | 4. 获取子系统菜单:localhost:9999/login/getMenus?hostName=www.baidu.com&callback=getMenus 16 | 5. 鉴权:localhost:9999/authorize?url=/civism/index.html会返回是否有权限 17 | # 说明 18 | * 除了以/login开头的不需要带token,其他的接口都需要把登录返回的token放到请求头中 19 | * 由于sso支持多个子系统,所有获取菜单的时候需要带域名,在数据库层次需要制定那些域名返回那些菜单,可以与权限集成,不同权限返回不同的菜单 20 | * 鉴权接口:该接口只验证了该用户在该角色的数据功能接口,所以设计数据库建议把菜单跟功能分离 21 | # 使用手册 22 | [使用说明](https://github.com/civism/civism-sso/wiki) 23 | # 具体接入介绍 24 | https://www.jianshu.com/p/1603c60f1de6 25 | -------------------------------------------------------------------------------- /http/civism-sso.http: -------------------------------------------------------------------------------- 1 | ### 鉴权 2 | GET http://localhost:8081/sso/auth 3 | Accept: application/json 4 | Token: 871138b5458c45f3a6a9b09235bdbde9 5 | 6 | 7 | ### 登录信息 8 | POST http://localhost:8081/sso/login 9 | Content-Type: application/json 10 | 11 | { 12 | "userName": "admin", 13 | "password": "123456" 14 | } 15 | 16 | ### 17 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.2.1.RELEASE 10 | 11 | 12 | com.civism 13 | sso 14 | 2.0.0-SNAPSHOT 15 | sso 16 | sso-web 17 | 18 | 19 | 1.8 20 | 1.4.2 21 | 3.2.0 22 | 1.1.21 23 | 2.1.1 24 | 1.2.10 25 | 2.9.2 26 | 1.2.62 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.apache.shiro 34 | shiro-core 35 | ${shiro-version} 36 | 37 | 38 | org.apache.shiro 39 | shiro-web 40 | ${shiro-version} 41 | 42 | 43 | org.apache.shiro 44 | shiro-spring 45 | ${shiro-version} 46 | 47 | 48 | 49 | 50 | com.baomidou 51 | mybatis-plus-boot-starter 52 | ${mybatis-plus-version} 53 | 54 | 55 | 56 | com.baomidou 57 | mybatis-plus-generator 58 | 3.2.0 59 | 60 | 61 | 62 | 63 | com.alibaba 64 | druid-spring-boot-starter 65 | ${druid-spring-boot-version} 66 | 67 | 68 | 69 | org.mybatis.spring.boot 70 | mybatis-spring-boot-starter 71 | ${mybatis-spring-boot-version} 72 | 73 | 74 | 75 | com.github.pagehelper 76 | pagehelper-spring-boot-starter 77 | ${pagehelper-version} 78 | 79 | 80 | 81 | io.springfox 82 | springfox-swagger2 83 | ${springfox-swagger-version} 84 | 85 | 86 | 87 | io.springfox 88 | springfox-swagger-ui 89 | ${springfox-swagger-version} 90 | 91 | 92 | 93 | com.alibaba 94 | fastjson 95 | ${fastjosn-version} 96 | 97 | 98 | 99 | org.springframework.boot 100 | spring-boot-starter-aop 101 | 102 | 103 | 104 | org.apache.commons 105 | commons-lang3 106 | 107 | 108 | 109 | javax.servlet 110 | javax.servlet-api 111 | 112 | 113 | 114 | mysql 115 | mysql-connector-java 116 | 117 | 118 | 119 | 120 | org.springframework.boot 121 | spring-boot-starter 122 | 123 | 124 | 125 | org.springframework.boot 126 | spring-boot-starter-data-redis 127 | 128 | 129 | 130 | org.projectlombok 131 | lombok 132 | true 133 | 134 | 135 | org.springframework.boot 136 | spring-boot-starter-test 137 | test 138 | 139 | 140 | org.junit.vintage 141 | junit-vintage-engine 142 | 143 | 144 | 145 | 146 | org.springframework.boot 147 | spring-boot-starter-web 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | org.springframework.boot 156 | spring-boot-maven-plugin 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /sql/sso.sql: -------------------------------------------------------------------------------- 1 | #系统表 2 | CREATE TABLE `civism-sso`.`sso_product` 3 | ( 4 | `id` INT NOT NULL AUTO_INCREMENT, 5 | `name` VARCHAR(45) NOT NULL, 6 | `grd_delete` TINYINT(1) NOT NULL COMMENT '逻辑删除 0 正常1删除', 7 | `gmt_create` DATETIME NOT NULL, 8 | `gmt_modified` DATETIME NOT NULL, 9 | PRIMARY KEY (`id`) 10 | ); 11 | 12 | #用户表 13 | CREATE TABLE `civism-sso`.`sso_user` 14 | ( 15 | `id` INT NOT NULL AUTO_INCREMENT, 16 | `name` VARCHAR(45) NOT NULL, 17 | `password` VARCHAR(45) NOT NULL, 18 | `grd_delete` TINYINT(1) NOT NULL, 19 | `gmt_create` DATETIME NOT NULL, 20 | `gmt_modified` DATETIME NOT NULL, 21 | PRIMARY KEY (`id`) 22 | ); 23 | #菜单表 24 | CREATE TABLE `civism-sso`.`sso_menu` 25 | ( 26 | `id` INT NOT NULL AUTO_INCREMENT, 27 | `name` VARCHAR(45) NOT NULL COMMENT '菜单名称', 28 | `grd_delete` TINYINT(1) NOT NULL, 29 | `gmt_create` DATETIME NOT NULL, 30 | `gmt_modified` DATETIME NOT NULL, 31 | PRIMARY KEY (`id`) 32 | ); 33 | #功能表 34 | CREATE TABLE `civism-sso`.`sso_function` 35 | ( 36 | `id` INT NOT NULL AUTO_INCREMENT, 37 | `name` VARCHAR(45) NOT NULL, 38 | `url` VARCHAR(45) NOT NULL, 39 | `method` VARCHAR(45) NOT NULL, 40 | `menu_id` INT(11) NULL, 41 | `grd_delete` TINYINT(1) NOT NULL, 42 | `gmt_create` DATETIME NOT NULL, 43 | `gmt_modified` DATETIME NOT NULL, 44 | PRIMARY KEY (`id`) 45 | ); 46 | 47 | INSERT INTO `civism-sso`.`sso_user`(`name`, `password`, `grd_delete`, `gmt_create`, `gmt_modified`) VALUES ('admin', '123456', 0, now(),now()); 48 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/SsoApplication.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | /** 8 | * @author : Civism 9 | * @projectName : civism-sso 10 | * @E-mail : 695234456@qq.com 11 | */ 12 | @SpringBootApplication 13 | @MapperScan("com.civism.sso.dao") 14 | public class SsoApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(SsoApplication.class, args); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/aop/GlobalExceptionAop.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.aop; 2 | 3 | import com.civism.sso.entity.Response; 4 | import com.civism.sso.enums.CustomExceptionEnum; 5 | import com.civism.sso.exception.CustomException; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.aspectj.lang.ProceedingJoinPoint; 8 | import org.aspectj.lang.Signature; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * @author : Civism 15 | * @projectName : civism-sso 16 | * @E-mail : 695234456@qq.com 17 | */ 18 | @Component 19 | @Aspect 20 | @Slf4j 21 | public class GlobalExceptionAop { 22 | 23 | private final String POINT_CUT = "execution(public * com.civism.sso.controller.*.*(..))"; 24 | 25 | @Around(value = POINT_CUT) 26 | public Object around(ProceedingJoinPoint proceedingJoinPoint) { 27 | Signature signature = proceedingJoinPoint.getSignature(); 28 | long t = System.currentTimeMillis(); 29 | try { 30 | Object result = proceedingJoinPoint.proceed(); 31 | printErrorLog(proceedingJoinPoint, signature, t); 32 | return result; 33 | } catch (CustomException ex) { 34 | printErrorLog(proceedingJoinPoint, signature, t); 35 | return new Response<>(ex); 36 | } catch (Exception e) { 37 | printErrorLog(proceedingJoinPoint, signature, t); 38 | return new Response<>(CustomExceptionEnum.SYSTEM_ERROR); 39 | } catch (Throwable throwable) { 40 | printErrorLog(proceedingJoinPoint, signature, t); 41 | return new Response<>(CustomExceptionEnum.SYSTEM_ERROR); 42 | } 43 | } 44 | 45 | private void printErrorLog(ProceedingJoinPoint proceedingJoinPoint, Signature signature, long t) { 46 | log.info("类名:{}-方法名:{}-传入参数:{}###总共耗时:{}毫秒", signature.getDeclaringTypeName(), 47 | signature.getName(), proceedingJoinPoint.getArgs(), 48 | System.currentTimeMillis() - t); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/config/RedisAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.config; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.redis.connection.RedisConnectionFactory; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | 9 | /** 10 | * @author : Civism 11 | * @projectName : civism-sso 12 | * @E-mail : 695234456@qq.com 13 | */ 14 | @Configuration 15 | public class RedisAutoConfiguration { 16 | 17 | 18 | @Bean 19 | @ConditionalOnMissingBean(name = "redisTemplate") 20 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 21 | RedisTemplate template = new RedisTemplate<>(); 22 | template.setConnectionFactory(redisConnectionFactory); 23 | return template; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/config/ShiroConfig.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.config; 2 | 3 | import com.civism.sso.filter.CheckLoginFilter; 4 | import com.civism.sso.filter.RefreshFilter; 5 | import com.civism.sso.shiro.*; 6 | import org.apache.shiro.mgt.SecurityManager; 7 | import org.apache.shiro.realm.Realm; 8 | import org.apache.shiro.session.mgt.SessionManager; 9 | import org.apache.shiro.session.mgt.eis.SessionDAO; 10 | import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 11 | import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | 15 | import javax.servlet.Filter; 16 | import java.util.HashMap; 17 | import java.util.LinkedHashMap; 18 | import java.util.Map; 19 | 20 | /** 21 | * @author : Civism 22 | * @projectName : civism-sso 23 | * @E-mail : 695234456@qq.com 24 | */ 25 | @Configuration 26 | public class ShiroConfig { 27 | 28 | @Bean 29 | public SessionManager sessionManager() { 30 | ShiroSessionManager shiroSessionManager = new ShiroSessionManager(); 31 | shiroSessionManager.setGlobalSessionTimeout(86400000); 32 | shiroSessionManager.setDeleteInvalidSessions(true); 33 | shiroSessionManager.setSessionValidationInterval(1800000); 34 | 35 | shiroSessionManager.setSessionDAO(getSession()); 36 | shiroSessionManager.getSessionIdCookie().setName("SHIRO-SESSIONID"); 37 | //是否开启定时调度器进行检测过期session 默认为true 38 | shiroSessionManager.setSessionValidationSchedulerEnabled(true); 39 | //取消url 后面的 JSESSIONID 40 | shiroSessionManager.setSessionIdUrlRewritingEnabled(false); 41 | return shiroSessionManager; 42 | } 43 | 44 | @Bean 45 | public SessionDAO getSession() { 46 | ShiroRedisCacheSessionDAO shiroRedisCacheSessionDAO = new ShiroRedisCacheSessionDAO(); 47 | shiroRedisCacheSessionDAO.setSessionIdGenerator(new JavaUuidSessionIdGenerator()); 48 | return shiroRedisCacheSessionDAO; 49 | } 50 | 51 | @Bean 52 | public CheckLoginFilter getCheckLoginFilter() { 53 | return new CheckLoginFilter(); 54 | } 55 | 56 | @Bean 57 | public RefreshFilter getRefreshFilter() { 58 | return new RefreshFilter(); 59 | } 60 | 61 | @Bean 62 | public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { 63 | ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); 64 | shiroFilterFactoryBean.setSecurityManager(securityManager); 65 | 66 | Map filters = new HashMap<>(); 67 | 68 | filters.put("checkLogin", getCheckLoginFilter()); 69 | filters.put("refresh", getCheckLoginFilter()); 70 | 71 | shiroFilterFactoryBean.setFilters(filters); 72 | 73 | //拦截器. 74 | Map filterChainDefinitionMap = new LinkedHashMap<>(); 75 | 76 | filterChainDefinitionMap.put("/sso/login", "anon"); 77 | filterChainDefinitionMap.put("/**", "checkLogin,refresh"); 78 | shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); 79 | return shiroFilterFactoryBean; 80 | } 81 | 82 | @Bean 83 | public SecurityManager getSecurityManager() { 84 | DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); 85 | defaultWebSecurityManager.setSessionManager(sessionManager()); 86 | defaultWebSecurityManager.setRealm(getRealm()); 87 | return defaultWebSecurityManager; 88 | } 89 | 90 | @Bean 91 | public Realm getRealm() { 92 | CivismShiroUpmsRealm civismShiroUpmsRealm = new CivismShiroUpmsRealm(); 93 | UrlPermissionResolver urlPermissionResolver = new UrlPermissionResolver(); 94 | // CustomRolePermissionResolver customRolePermissionResolver = new CustomRolePermissionResolver(); 95 | // civismShiroUpmsRealm.setRolePermissionResolver(customRolePermissionResolver); 96 | civismShiroUpmsRealm.setPermissionResolver(urlPermissionResolver); 97 | return civismShiroUpmsRealm; 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/config/ShiroFilterRegisterConfig.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.config; 2 | 3 | 4 | import com.civism.sso.filter.CheckLoginFilter; 5 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | /** 10 | * @author : Civism 11 | * @projectName : civism-sso 12 | * @E-mail : 695234456@qq.com 13 | */ 14 | @Configuration 15 | public class ShiroFilterRegisterConfig { 16 | 17 | @Bean 18 | public FilterRegistrationBean permissionFilterRegistration(CheckLoginFilter filter) { 19 | FilterRegistrationBean registration = new FilterRegistrationBean(filter); 20 | registration.setEnabled(false); 21 | return registration; 22 | } 23 | // 24 | // @Bean 25 | // public FilterRegistrationBean refreshFilterRegistration(RefreshFilter filter) { 26 | // FilterRegistrationBean registration = new FilterRegistrationBean(filter); 27 | // registration.setEnabled(false); 28 | // return registration; 29 | // } 30 | // 31 | // @Bean 32 | // public FilterRegistrationBean infoPowerRegistration(InfoPowerFilter filter){ 33 | // FilterRegistrationBean registration = new FilterRegistrationBean(filter); 34 | // registration.setEnabled(false); 35 | // return registration; 36 | // } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.config; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.ParameterBuilder; 8 | import springfox.documentation.builders.PathSelectors; 9 | import springfox.documentation.builders.RequestHandlerSelectors; 10 | import springfox.documentation.schema.ModelRef; 11 | import springfox.documentation.service.ApiInfo; 12 | import springfox.documentation.service.Parameter; 13 | import springfox.documentation.spi.DocumentationType; 14 | import springfox.documentation.spring.web.plugins.Docket; 15 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * @author : Civism 22 | * @projectName : civism-sso 23 | * @E-mail : 695234456@qq.com 24 | */ 25 | @Configuration 26 | @EnableSwagger2 27 | @ConditionalOnProperty(prefix = "swagger", value = {"enable"}, havingValue = "true") 28 | public class SwaggerConfig { 29 | 30 | @Bean 31 | public Docket createRestApi() { 32 | ParameterBuilder tokenPar = new ParameterBuilder(); 33 | List pars = new ArrayList<>(); 34 | tokenPar.name("token").description("令牌") 35 | .modelRef(new ModelRef("string")).parameterType("header").required(true).build(); 36 | pars.add(tokenPar.build()); 37 | return new Docket(DocumentationType.SWAGGER_2) 38 | .apiInfo(apiInfo()) 39 | .select() 40 | .apis(RequestHandlerSelectors.basePackage("com.xc.info.controller")) 41 | .paths(PathSelectors.any()) 42 | .build().globalOperationParameters(pars); 43 | } 44 | 45 | 46 | private ApiInfo apiInfo() { 47 | return new ApiInfoBuilder() 48 | .title("基础信息管理") 49 | .description("基础信息接口文档") 50 | .version("2.0.0") 51 | .build(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/constant/CivismConstant.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.constant; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author : Civism 7 | * @projectName : civism-sso 8 | * @E-mail : 695234456@qq.com 9 | */ 10 | public class CivismConstant implements Serializable { 11 | 12 | private static final long serialVersionUID = 1751077975755493749L; 13 | 14 | /** 15 | * redis中的token 16 | */ 17 | public static final String TOKEN = "token"; 18 | 19 | /** 20 | * 登陆有效期 21 | */ 22 | public static final Long EXPIRE = 30 * 60 * 1L; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.controller; 2 | 3 | import com.civism.sso.entity.LoginEntity; 4 | import io.swagger.annotations.Api; 5 | import io.swagger.annotations.ApiOperation; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.apache.shiro.SecurityUtils; 8 | import org.apache.shiro.authc.UsernamePasswordToken; 9 | import org.apache.shiro.subject.Subject; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | 14 | /** 15 | * @author : Civism 16 | * @projectName : civism-sso 17 | * @E-mail : 695234456@qq.com 18 | */ 19 | @RestController 20 | @RequestMapping("/sso") 21 | @Api(tags = "登陆接口") 22 | @Slf4j 23 | public class IndexController { 24 | 25 | 26 | @ApiOperation("登陆") 27 | @PostMapping("/login") 28 | public Object login(@RequestBody LoginEntity loginEntity) { 29 | UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(); 30 | usernamePasswordToken.setUsername(loginEntity.getUserName()); 31 | usernamePasswordToken.setPassword(loginEntity.getPassword().toCharArray()); 32 | Subject subject = SecurityUtils.getSubject(); 33 | subject.login(usernamePasswordToken); 34 | if (subject.isAuthenticated()) { 35 | return SecurityUtils.getSubject().getPrincipal(); 36 | } 37 | return null; 38 | } 39 | 40 | @ApiOperation("鉴权") 41 | @GetMapping("/auth") 42 | public Boolean authenticate(HttpServletRequest request) { 43 | String servletPath = request.getServletPath(); 44 | return SecurityUtils.getSubject().isPermitted(servletPath); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/dao/SsoFunctionDao.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.dao; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.civism.sso.entity.SsoFunctionDO; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public interface SsoFunctionDao extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/dao/SsoProductDao.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.dao; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.civism.sso.entity.SsoProductDO; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public interface SsoProductDao extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/dao/SsoUserDao.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.dao; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.civism.sso.entity.SsoUserDO; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public interface SsoUserDao extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/entity/AuthEntity.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author : Civism 7 | * @projectName : civism-sso 8 | * @E-mail : 695234456@qq.com 9 | */ 10 | public class AuthEntity implements Serializable { 11 | 12 | private static final long serialVersionUID = 139913275235343163L; 13 | 14 | 15 | private String requestUrl; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/entity/BaseDO.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableLogic; 6 | import lombok.Data; 7 | 8 | import java.io.Serializable; 9 | import java.util.Date; 10 | /** 11 | * @author : Civism 12 | * @projectName : civism-sso 13 | * @E-mail : 695234456@qq.com 14 | */ 15 | @Data 16 | public class BaseDO implements Serializable { 17 | 18 | private static final long serialVersionUID = -5048221139649128719L; 19 | 20 | @TableId(type = IdType.AUTO) 21 | private Integer id; 22 | 23 | private Date gmtCreate; 24 | 25 | private Date gmtModified; 26 | 27 | @TableLogic 28 | private Integer grdDelete; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/entity/LoginEntity.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.entity; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | /** 8 | * @author : Civism 9 | * @projectName : civism-sso 10 | * @E-mail : 695234456@qq.com 11 | */ 12 | @Data 13 | public class LoginEntity implements Serializable { 14 | 15 | private static final long serialVersionUID = 2449244918272018993L; 16 | 17 | /** 18 | * 用户名称 19 | */ 20 | @ApiModelProperty("用户名称") 21 | private String userName; 22 | 23 | /** 24 | * 用户密码 25 | */ 26 | @ApiModelProperty("用户密码") 27 | private String password; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/entity/Response.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.entity; 2 | 3 | import com.civism.sso.exception.CustomException; 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public class Response implements Serializable { 12 | 13 | private static final long serialVersionUID = 8817463078594954274L; 14 | 15 | private boolean success; 16 | 17 | private T data; 18 | 19 | private String errorCode; 20 | 21 | private String errorMsg; 22 | 23 | 24 | public Response(T data) { 25 | if (data instanceof CustomException) { 26 | CustomException customException = (CustomException) data; 27 | this.errorCode = customException.getErrorCode(); 28 | this.errorMsg = customException.getErrorMsg(); 29 | } else { 30 | this.data = data; 31 | this.success = true; 32 | } 33 | } 34 | 35 | 36 | public boolean isSuccess() { 37 | return success; 38 | } 39 | 40 | public void setSuccess(boolean success) { 41 | this.success = success; 42 | } 43 | 44 | public T getData() { 45 | return data; 46 | } 47 | 48 | public void setData(T data) { 49 | this.data = data; 50 | } 51 | 52 | public String getErrorCode() { 53 | return errorCode; 54 | } 55 | 56 | public void setErrorCode(String errorCode) { 57 | this.errorCode = errorCode; 58 | } 59 | 60 | public String getErrorMsg() { 61 | return errorMsg; 62 | } 63 | 64 | public void setErrorMsg(String errorMsg) { 65 | this.errorMsg = errorMsg; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/entity/SsoFunctionDO.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | @Data 12 | @TableName("sso_function") 13 | public class SsoFunctionDO extends BaseDO { 14 | 15 | private static final long serialVersionUID = -420032538363892799L; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/entity/SsoProductDO.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | @Data 12 | @TableName("sso_product") 13 | public class SsoProductDO extends BaseDO { 14 | 15 | private static final long serialVersionUID = 5019247183721310811L; 16 | 17 | private String name; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/entity/SsoUserDO.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.TableName; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | @Data 12 | @TableName("sso_user") 13 | public class SsoUserDO extends BaseDO { 14 | 15 | private static final long serialVersionUID = -898944646564104445L; 16 | 17 | /** 18 | * 账号密码 19 | */ 20 | private String name; 21 | 22 | /** 23 | * 密码 24 | */ 25 | private String password; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/entity/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * @author : Civism 12 | * @projectName : civism-sso 13 | * @E-mail : 695234456@qq.com 14 | */ 15 | @Builder 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class UserInfo implements Serializable { 20 | 21 | private static final long serialVersionUID = -2253372833687147328L; 22 | 23 | /** 24 | * 用户id 25 | */ 26 | private Integer id; 27 | 28 | /** 29 | * 用户名称 30 | */ 31 | private String name; 32 | 33 | /** 34 | * 用户token 35 | */ 36 | private String token; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/enums/CustomExceptionEnum.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.enums; 2 | 3 | /** 4 | * @author : Civism 5 | * @version 1.0 6 | * @projectName:civism-sso 7 | * @E-mail:695234456@qq.com 8 | */ 9 | public enum CustomExceptionEnum { 10 | ACCOUNT_PASSWORD_ERROR("U001", "用户名或密码错误"), 11 | NO_LOGIN("U002", "登陆过期"), 12 | NO_POWER("U003", "没有权限"), 13 | SYSTEM_ERROR("Z999", "系统异常"); 14 | 15 | CustomExceptionEnum(String code, String errorMsg) { 16 | this.code = code; 17 | this.errorMsg = errorMsg; 18 | } 19 | 20 | private String code; 21 | 22 | private String errorMsg; 23 | 24 | public String getCode() { 25 | return code; 26 | } 27 | 28 | public void setCode(String code) { 29 | this.code = code; 30 | } 31 | 32 | public String getErrorMsg() { 33 | return errorMsg; 34 | } 35 | 36 | public void setErrorMsg(String errorMsg) { 37 | this.errorMsg = errorMsg; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/exception/CustomException.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.exception; 2 | 3 | import com.civism.sso.enums.CustomExceptionEnum; 4 | import org.apache.shiro.authc.AuthenticationException; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public class CustomException extends AuthenticationException { 12 | 13 | private String errorCode; 14 | private String errorMsg; 15 | 16 | public CustomException(CustomExceptionEnum exceptionEnum) { 17 | this.errorCode = exceptionEnum.getCode(); 18 | this.errorMsg = exceptionEnum.getErrorMsg(); 19 | } 20 | 21 | 22 | public String getErrorCode() { 23 | return errorCode; 24 | } 25 | 26 | public String getErrorMsg() { 27 | return errorMsg; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/filter/BaseCheckFilter.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.filter; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.civism.sso.entity.Response; 5 | import com.civism.sso.exception.CustomException; 6 | import org.apache.shiro.web.filter.authc.UserFilter; 7 | 8 | import javax.servlet.ServletRequest; 9 | import javax.servlet.ServletResponse; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.PrintWriter; 12 | 13 | /** 14 | * @author : Civism 15 | * @projectName : civism-sso 16 | * @E-mail : 695234456@qq.com 17 | */ 18 | public abstract class BaseCheckFilter extends UserFilter { 19 | 20 | protected abstract void checkFail() throws CustomException; 21 | 22 | @Override 23 | protected boolean onAccessDenied(ServletRequest req, ServletResponse resp) 24 | throws Exception { 25 | 26 | PrintWriter out = null; 27 | try { 28 | checkFail(); 29 | return super.onAccessDenied(req, resp); 30 | } catch (CustomException e) { 31 | HttpServletResponse response = (HttpServletResponse) resp; 32 | response.setCharacterEncoding("UTF-8"); 33 | response.setHeader("Content-Type", "application/json;charset=utf-8"); 34 | response.setContentType("application/json;charset=UTF-8"); 35 | out = response.getWriter(); 36 | out.write(JSON.toJSONString(new Response<>(e))); 37 | } finally { 38 | if (out != null) { 39 | out.close(); 40 | } 41 | } 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/filter/CheckLoginFilter.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.filter; 2 | 3 | import com.civism.sso.constant.CivismConstant; 4 | import com.civism.sso.enums.CustomExceptionEnum; 5 | import com.civism.sso.exception.CustomException; 6 | import com.civism.sso.redis.RedisClient; 7 | import org.apache.commons.lang3.StringUtils; 8 | 9 | import javax.annotation.Resource; 10 | import javax.servlet.ServletRequest; 11 | import javax.servlet.ServletResponse; 12 | import javax.servlet.http.HttpServletRequest; 13 | 14 | /** 15 | * @author : Civism 16 | * @projectName : civism-sso 17 | * @E-mail : 695234456@qq.com 18 | */ 19 | public class CheckLoginFilter extends BaseCheckFilter { 20 | 21 | @Resource 22 | private RedisClient redisClient; 23 | 24 | @Override 25 | protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue) { 26 | 27 | HttpServletRequest request = (HttpServletRequest) req; 28 | String token = request.getHeader(CivismConstant.TOKEN); 29 | if (StringUtils.isEmpty(token)) { 30 | return false; 31 | } 32 | Object o = redisClient.get(token); 33 | return o != null; 34 | 35 | 36 | } 37 | 38 | @Override 39 | protected void checkFail() throws CustomException { 40 | throw new CustomException(CustomExceptionEnum.NO_LOGIN); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/filter/RefreshFilter.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.filter; 2 | 3 | import com.civism.sso.redis.RedisClient; 4 | import org.apache.shiro.web.filter.authc.UserFilter; 5 | 6 | import javax.annotation.Resource; 7 | import javax.servlet.ServletRequest; 8 | import javax.servlet.ServletResponse; 9 | import javax.servlet.http.HttpServletRequest; 10 | 11 | import static com.civism.sso.constant.CivismConstant.EXPIRE; 12 | import static com.civism.sso.constant.CivismConstant.TOKEN; 13 | 14 | /** 15 | * @author : Civism 16 | * @projectName : civism-sso 17 | * @E-mail : 695234456@qq.com 18 | */ 19 | public class RefreshFilter extends UserFilter { 20 | 21 | @Resource 22 | private RedisClient redisClient; 23 | 24 | @Override 25 | protected boolean isAccessAllowed(ServletRequest req, ServletResponse response, Object mappedValue) { 26 | HttpServletRequest request = (HttpServletRequest) req; 27 | String token = request.getHeader(TOKEN); 28 | redisClient.expire(token, EXPIRE); 29 | return super.isAccessAllowed(request, response, mappedValue); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/redis/RedisClient.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.redis; 2 | 3 | import org.springframework.data.redis.core.RedisTemplate; 4 | import org.springframework.stereotype.Component; 5 | 6 | import javax.annotation.Resource; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * @author : Civism 11 | * @projectName : civism-sso 12 | * @E-mail : 695234456@qq.com 13 | */ 14 | @Component 15 | public class RedisClient { 16 | 17 | @Resource 18 | private RedisTemplate redisTemplate; 19 | 20 | /** 21 | * 设置过期时间 22 | * 23 | * @param timeOut 超时时间 单位秒 24 | */ 25 | public void set(String key, Object value, long timeOut) { 26 | redisTemplate.opsForValue().set(key, value, timeOut, TimeUnit.SECONDS); 27 | } 28 | 29 | /** 30 | * 永不过期(相对意义) 31 | */ 32 | public void set(String key, Object value) { 33 | redisTemplate.opsForValue().set(key, value); 34 | } 35 | 36 | /** 37 | * 删除 38 | */ 39 | public boolean delete(String key) { 40 | return redisTemplate.delete(key); 41 | } 42 | 43 | /** 44 | * 45 | */ 46 | public Object get(String key) { 47 | return redisTemplate.opsForValue().get(key); 48 | } 49 | 50 | /** 51 | * 刷新key实效 52 | * @param key 53 | * @param time 54 | */ 55 | public void expire(String key, long time) { 56 | redisTemplate.expire(key, time, TimeUnit.SECONDS); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/service/SsoFunctionService.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.civism.sso.entity.SsoFunctionDO; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public interface SsoFunctionService extends IService { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/service/SsoProductService.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.civism.sso.entity.SsoProductDO; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public interface SsoProductService extends IService { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/service/SsoUserService.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.civism.sso.entity.SsoUserDO; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public interface SsoUserService extends IService { 12 | 13 | /** 14 | * 通过用户名和密码查找用户 15 | * @param userName 16 | * @return 17 | */ 18 | SsoUserDO queryUserByUserName(String userName); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/service/impl/SsoFunctionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.service.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.civism.sso.dao.SsoFunctionDao; 5 | import com.civism.sso.entity.SsoFunctionDO; 6 | import com.civism.sso.service.SsoFunctionService; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * @author : Civism 11 | * @projectName : civism-sso 12 | * @E-mail : 695234456@qq.com 13 | */ 14 | @Service 15 | public class SsoFunctionServiceImpl extends ServiceImpl implements SsoFunctionService { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/service/impl/SsoProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.service.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.civism.sso.dao.SsoProductDao; 5 | import com.civism.sso.entity.SsoProductDO; 6 | import com.civism.sso.service.SsoProductService; 7 | import org.springframework.stereotype.Service; 8 | /** 9 | * @author : Civism 10 | * @projectName : civism-sso 11 | * @E-mail : 695234456@qq.com 12 | */ 13 | @Service 14 | public class SsoProductServiceImpl extends ServiceImpl implements SsoProductService { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/service/impl/SsoUserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 5 | import com.civism.sso.dao.SsoUserDao; 6 | import com.civism.sso.entity.SsoUserDO; 7 | import com.civism.sso.service.SsoUserService; 8 | import org.springframework.stereotype.Service; 9 | 10 | /** 11 | * @author : Civism 12 | * @projectName : civism-sso 13 | * @E-mail : 695234456@qq.com 14 | */ 15 | @Service 16 | public class SsoUserServiceImpl extends ServiceImpl implements SsoUserService { 17 | 18 | @Override 19 | public SsoUserDO queryUserByUserName(String userName) { 20 | return this.getOne(Wrappers.lambdaQuery().eq(SsoUserDO::getName, userName)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/shiro/CivismShiroUpmsRealm.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.shiro; 2 | 3 | import com.civism.sso.constant.CivismConstant; 4 | import com.civism.sso.entity.SsoUserDO; 5 | import com.civism.sso.entity.UserInfo; 6 | import com.civism.sso.enums.CustomExceptionEnum; 7 | import com.civism.sso.exception.CustomException; 8 | import com.civism.sso.redis.RedisClient; 9 | import com.civism.sso.service.SsoUserService; 10 | import org.apache.shiro.SecurityUtils; 11 | import org.apache.shiro.authc.AuthenticationException; 12 | import org.apache.shiro.authc.AuthenticationInfo; 13 | import org.apache.shiro.authc.AuthenticationToken; 14 | import org.apache.shiro.authc.SimpleAuthenticationInfo; 15 | import org.apache.shiro.authz.AuthorizationInfo; 16 | import org.apache.shiro.authz.SimpleAuthorizationInfo; 17 | import org.apache.shiro.realm.AuthorizingRealm; 18 | import org.apache.shiro.subject.PrincipalCollection; 19 | 20 | import javax.annotation.Resource; 21 | import java.io.Serializable; 22 | import java.util.HashSet; 23 | import java.util.Set; 24 | 25 | /** 26 | * @author : Civism 27 | * @projectName : civism-sso 28 | * @E-mail : 695234456@qq.com 29 | */ 30 | public class CivismShiroUpmsRealm extends AuthorizingRealm { 31 | 32 | 33 | @Resource 34 | private SsoUserService ssoUserService; 35 | 36 | @Resource 37 | private RedisClient redisClient; 38 | 39 | @Override 40 | protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 41 | UserInfo userInfo = (UserInfo) principalCollection.getPrimaryPrincipal(); 42 | 43 | //根据用户查询有数据接口权限 44 | SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 45 | Set urlSet = new HashSet<>(); 46 | urlSet.add("/sso/auth"); 47 | info.setStringPermissions(urlSet); 48 | 49 | // info.setRoles(Sets.newHashSet("admin")); 50 | return info; 51 | } 52 | 53 | @Override 54 | protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { 55 | 56 | 57 | Object principal = authenticationToken.getPrincipal(); 58 | 59 | SsoUserDO ssoUserDO = ssoUserService.queryUserByUserName((String) principal); 60 | if (ssoUserDO == null) { 61 | throw new CustomException(CustomExceptionEnum.ACCOUNT_PASSWORD_ERROR); 62 | } 63 | 64 | Serializable token = SecurityUtils.getSubject().getSession().getId(); 65 | 66 | UserInfo userInfo = UserInfo.builder().name(ssoUserDO.getName()) 67 | .token((String) token).id(ssoUserDO.getId()).build(); 68 | redisClient.set((String) token, userInfo, CivismConstant.EXPIRE); 69 | return new SimpleAuthenticationInfo(userInfo, ssoUserDO.getPassword(), 70 | getName()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/shiro/CustomRolePermissionResolver.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.shiro; 2 | 3 | import org.apache.shiro.authz.Permission; 4 | import org.apache.shiro.authz.permission.RolePermissionResolver; 5 | 6 | import java.util.Collection; 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | 10 | /** 11 | * @author : Civism 12 | * @version 1.0 13 | * @projectName:civism-sso 14 | * @Time: 2020-09-18 15 | * @E-mail:695234456@qq.com 16 | */ 17 | public class CustomRolePermissionResolver implements RolePermissionResolver { 18 | 19 | @Override 20 | public Collection resolvePermissionsInRole(String s) { 21 | 22 | 23 | 24 | List roleList = new LinkedList<>(); 25 | roleList.add(new RolePermission(s)); 26 | return roleList; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/shiro/JavaUuidSessionIdGenerator.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.shiro; 2 | 3 | import org.apache.shiro.session.Session; 4 | import org.apache.shiro.session.mgt.eis.SessionIdGenerator; 5 | 6 | import java.io.Serializable; 7 | import java.util.UUID; 8 | 9 | /** 10 | * @author : Civism 11 | * @projectName : civism-sso 12 | * @E-mail : 695234456@qq.com 13 | */ 14 | public class JavaUuidSessionIdGenerator implements SessionIdGenerator { 15 | 16 | public JavaUuidSessionIdGenerator() { 17 | } 18 | 19 | 20 | @Override 21 | public Serializable generateId(Session session) { 22 | return UUID.randomUUID().toString().replaceAll("-", ""); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/shiro/RolePermission.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.shiro; 2 | 3 | import org.apache.shiro.authz.Permission; 4 | 5 | /** 6 | * @author : Civism 7 | * @version 1.0 8 | * @projectName:civism-sso 9 | * @Time: 2020-09-18 10 | * @E-mail:695234456@qq.com 11 | */ 12 | public class RolePermission implements Permission { 13 | 14 | private String role; 15 | 16 | 17 | public RolePermission(String role) { 18 | this.role = role; 19 | } 20 | 21 | @Override 22 | public boolean implies(Permission permission) { 23 | 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/shiro/ShiroRedisCacheSessionDAO.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.shiro; 2 | 3 | import com.civism.sso.redis.RedisClient; 4 | import org.apache.shiro.session.Session; 5 | import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; 6 | 7 | import javax.annotation.Resource; 8 | import java.io.Serializable; 9 | 10 | /** 11 | * @author : Civism 12 | * @projectName : civism-sso 13 | * @E-mail : 695234456@qq.com 14 | */ 15 | public class ShiroRedisCacheSessionDAO extends EnterpriseCacheSessionDAO { 16 | 17 | 18 | private static final String REDIS_KEY = "civism-sso-redis-"; 19 | 20 | @Resource 21 | private RedisClient redisClient; 22 | 23 | @Override 24 | protected Serializable doCreate(Session session) { 25 | 26 | Serializable serializable = super.doCreate(session); 27 | redisClient.set(REDIS_KEY + serializable, session, (int) session.getTimeout() / 1000); 28 | return serializable; 29 | } 30 | 31 | @Override 32 | protected Session doReadSession(Serializable sessionId) { 33 | Session session = super.doReadSession(sessionId); 34 | if (session == null) { 35 | session = (Session) redisClient.get(REDIS_KEY + sessionId); 36 | } 37 | return session; 38 | } 39 | 40 | @Override 41 | protected void doUpdate(Session session) { 42 | super.doUpdate(session); 43 | redisClient.set(REDIS_KEY + session.getId(), session, (int) session.getTimeout() / 1000); 44 | } 45 | 46 | @Override 47 | protected void doDelete(Session session) { 48 | super.doDelete(session); 49 | redisClient.delete(REDIS_KEY + session.getId()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/shiro/ShiroSessionManager.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.shiro; 2 | 3 | import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; 4 | 5 | import javax.servlet.ServletRequest; 6 | import javax.servlet.ServletResponse; 7 | import javax.servlet.http.HttpServletRequest; 8 | import java.io.Serializable; 9 | 10 | 11 | /** 12 | * @author : Civism 13 | * @projectName : civism-sso 14 | * @E-mail : 695234456@qq.com 15 | */ 16 | public class ShiroSessionManager extends DefaultWebSessionManager { 17 | 18 | 19 | @Override 20 | protected Serializable getSessionId(ServletRequest httpRequest, ServletResponse response) { 21 | HttpServletRequest request = (HttpServletRequest) httpRequest; 22 | return request.getHeader("token"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/shiro/UrlPathMatcher.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.shiro; 2 | 3 | import org.apache.shiro.util.PatternMatcher; 4 | 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | /** 9 | * @author : Civism 10 | * @projectName : civism-sso 11 | * @E-mail : 695234456@qq.com 12 | */ 13 | public class UrlPathMatcher implements PatternMatcher { 14 | 15 | @Override 16 | public boolean matches(String p, String source) { 17 | if (p.equals(source)) { 18 | return true; 19 | } else { 20 | //原始路径, source请求路径 21 | Pattern pattern = Pattern.compile(p); 22 | Matcher matcher = pattern.matcher(source); 23 | return matcher.matches(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/shiro/UrlPermission.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.shiro; 2 | 3 | import org.apache.shiro.authz.Permission; 4 | import org.apache.shiro.util.PatternMatcher; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public class UrlPermission implements Permission { 12 | 13 | 14 | private String url; 15 | 16 | public UrlPermission(String url) { 17 | this.url = url; 18 | } 19 | 20 | @Override 21 | public boolean implies(Permission p) { 22 | if (!(p instanceof UrlPermission)) { 23 | return false; 24 | } 25 | UrlPermission urlPermission = (UrlPermission) p; 26 | PatternMatcher patternMatcher = new UrlPathMatcher(); 27 | return patternMatcher.matches(this.url, urlPermission.url); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/civism/sso/shiro/UrlPermissionResolver.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso.shiro; 2 | 3 | import org.apache.shiro.authz.Permission; 4 | import org.apache.shiro.authz.permission.PermissionResolver; 5 | 6 | /** 7 | * @author : Civism 8 | * @projectName : civism-sso 9 | * @E-mail : 695234456@qq.com 10 | */ 11 | public class UrlPermissionResolver implements PermissionResolver { 12 | @Override 13 | public Permission resolvePermission(String permissionString) { 14 | return new UrlPermission(permissionString); 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8081 3 | spring: 4 | http: 5 | encoding: 6 | charset: UTF-8 7 | force: true 8 | enabled: true 9 | datasource: 10 | url: jdbc:mysql://127.0.0.1:3306/civism-sso?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false 11 | username: root 12 | password: 123456 13 | type: com.alibaba.druid.pool.DruidDataSource 14 | filters: stat 15 | maxActive: 20 16 | initialSize: 1 17 | maxWait: 60000 18 | minIdle: 1 19 | timeBetweenEvictionRunsMillis: 60000 20 | minEvictableIdleTimeMillis: 300000 21 | validationQuery: select 'x' 22 | testWhileIdle: true 23 | testOnBorrow: false 24 | testOnReturn: false 25 | poolPreparedStatements: true 26 | maxOpenPreparedStatements: 20 27 | main: 28 | allow-bean-definition-overriding: true 29 | jackson: 30 | default-property-inclusion: non_null 31 | date-format: yyyy-MM-dd HH:mm:ss 32 | servlet: 33 | multipart: 34 | max-file-size: 2MB 35 | max-request-size: 10MB 36 | redis: 37 | host: 127.0.0.1 38 | port: 6379 39 | password: 40 | aop: 41 | proxy-target-class: true 42 | 43 | ## 该配置节点为独立的节点,有很多同学容易将这个配置放在spring的节点下,导致配置无法被识别 44 | mybatis: 45 | mapper-locations: classpath*:mapper/*.xml #注意:一定要对应mapper映射xml文件的所在路径 46 | type-aliases-package: com.civism.sso.entity # 注意:对应实体类的路径 47 | 48 | #pagehelper分页插件 49 | pagehelper: 50 | helperDialect: mysql 51 | reasonable: false 52 | supportMethodsArguments: true 53 | params: count=countSql 54 | #文档接口 55 | swagger: 56 | enable: true -------------------------------------------------------------------------------- /src/main/resources/mapper/sso_product.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/test/java/com/civism/sso/SsoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.civism.sso; 2 | 3 | import com.civism.sso.entity.SsoProductDO; 4 | import com.civism.sso.service.SsoProductService; 5 | import com.github.pagehelper.PageHelper; 6 | import com.github.pagehelper.PageInfo; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.List; 13 | 14 | @SpringBootTest 15 | public class SsoApplicationTests { 16 | 17 | @Resource 18 | private SsoProductService ssoProductService; 19 | 20 | @Resource 21 | private RedisTemplate redisTemplate; 22 | 23 | @Test 24 | public void 测试redis() { 25 | redisTemplate.opsForValue().set("star", "123"); 26 | 27 | Object star = redisTemplate.opsForValue().get("star"); 28 | System.out.println(star); 29 | } 30 | 31 | @Test 32 | void contextLoads() { 33 | PageHelper.startPage(1, 10); 34 | List list = ssoProductService.list(); 35 | PageInfo pageInfo = new PageInfo<>(list); 36 | 37 | System.out.println(pageInfo); 38 | } 39 | 40 | } 41 | --------------------------------------------------------------------------------