├── README.md ├── fp-authorization-server ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── wwz │ │ └── frame │ │ ├── AuthorizationServerApplication.java │ │ ├── config │ │ ├── MyAccessDeniedHandler.java │ │ ├── MyLoginAuthFailureHandler.java │ │ ├── MyLoginAuthSuccessHandler.java │ │ ├── MySecurityConfig.java │ │ ├── MySecurityOAuth2Config.java │ │ ├── MySecurityResourceServerConfig.java │ │ ├── MyTokenEnhancer.java │ │ ├── MyTokenExceptionEntryPoint.java │ │ └── RestTemplateClientConfig.java │ │ ├── controller │ │ └── TokenController.java │ │ ├── exception │ │ ├── MyOAuth2Exception.java │ │ ├── MyOAuth2WebResponseExceptionTranslator.java │ │ └── MyOAuthExceptionJacksonSerializer.java │ │ ├── filter │ │ ├── ClientDetailsAuthenticationFilter.java │ │ └── MyPhoneLoginAuthenticationFilter.java │ │ ├── mapper │ │ ├── AuthClientDetailsMapper.java │ │ ├── AuthPermissionMapper.java │ │ ├── AuthRoleMapper.java │ │ └── AuthUserMapper.java │ │ ├── provider │ │ ├── MyAbstractUserDetailsAuthenticationProvider.java │ │ └── MyPhoneAuthenticationProvider.java │ │ ├── service │ │ ├── MyClientDetails.java │ │ ├── MyClientDetailsService.java │ │ ├── MyPhoneUserDetailsService.java │ │ ├── MyUserDetails.java │ │ ├── MyUserDetailsService.java │ │ └── MyUsernameUserDetailsService.java │ │ └── token │ │ ├── MyAuthenticationToken.java │ │ └── MyPhoneAuthenticationToken.java │ └── resources │ ├── application-dev.yml │ ├── application-test.yml │ ├── application.yml │ └── bootstrap.yml ├── fp-commons ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── wwz │ └── frame │ ├── CommonsApplication.java │ ├── annotation │ └── OperationLog.java │ ├── common │ ├── CodeEnum.java │ ├── CommonUtils.java │ ├── HttpUtilsResultVO.java │ ├── LinkStringUtil.java │ └── ResponseVo.java │ └── entity │ ├── AuthClientDetails.java │ ├── AuthPermission.java │ ├── AuthResource.java │ ├── AuthRole.java │ ├── AuthUser.java │ └── OperateLog.java ├── fp-gateway ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── wwz │ │ └── frame │ │ └── GateWayApplication.java │ └── resources │ ├── application-dev.yml │ ├── application-test.yml │ ├── application.yml │ └── bootstrap.yml ├── fp-log └── pom.xml ├── fp-resource-feign ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── wwz │ │ └── frame │ │ ├── FeignClientApplication.java │ │ ├── config │ │ └── FeignConfig.java │ │ ├── controller │ │ └── TestFeignClientController.java │ │ └── feignclient │ │ └── ResourceManagerFeignClient.java │ └── resources │ ├── application-dev.yml │ ├── application-test.yml │ ├── application.yml │ └── bootstrap.yml ├── fp-resource-manager ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── wwz │ │ └── frame │ │ ├── AuthManagerApplication.java │ │ ├── config │ │ ├── MyAccessDeniedHandler.java │ │ ├── MyFilterInvocationSecurityMetadataSource.java │ │ ├── MySecurityAccessDecisionManager.java │ │ ├── MySecurityResourceServerConfig.java │ │ ├── MyTokenExceptionEntryPoint.java │ │ ├── SwaggerConfig.java │ │ └── SwaggerConfig2.java │ │ ├── controller │ │ ├── AuthController.java │ │ ├── AuthResourceController.java │ │ └── AuthUserController.java │ │ ├── service │ │ ├── AuthResourceService.java │ │ ├── MyUserDetails.java │ │ └── impl │ │ │ └── AuthResourceServiceImpl.java │ │ └── token │ │ ├── MyAuthenticationToken.java │ │ └── MyPhoneAuthenticationToken.java │ └── resources │ ├── application-dev.yml │ ├── application-test.yml │ ├── application.yml │ └── bootstrap.yml ├── frame-permission.sql └── pom.xml /README.md: -------------------------------------------------------------------------------- 1 | 2019.07.02 2 | 3 | 环境:SpringBoot 2.1.0.RELEASE jdk1.8 SpringCloud Greenwich.SR1 consul服务发现与注册 redis 4 | 5 | 目前完成: 6 | 7 | 1、请求前客户端信息完整性校验 8 | 2、自定义异常返回 9 | 3、无权处理器 10 | 4、token失效处理器 11 | 5、自定义token返回信息 12 | 6、根据请求URI拦截权限判断 13 | 7、登录登出自定义 14 | 8、用户名密码登录以及手机号码登录 15 | 9、 swagger 集成 OAuth2 16 | 10、Feign 权限处理 17 | 18 | 19 | 最近在使用SpringCloud 开发权限管理项目,于是设计了一个SpringSecurity OAuth2的统一安全认证。 20 | 1、环境 SpringBoot 2.1.0.RELEASE jdk1.8 SpringCloud Greenwich.SR1 consul服务发现与注册 21 | 2、项目划分 22 | 23 | (1)、fp-commons jar公用 24 | (2)、fp-gateway 网关 25 | (3)、fp-resource-manager 用户信息管理资源服务器 26 | (4)、fp-authorization-server OAuth2认证服务器 27 | (5)、fp-log 日志 28 | 3、 项目搭建 29 | (1)网关搭建 frame-gateway 30 | 31 | pom.xml: 32 | 引入依赖文件;在启动器上添加 注册监听@EnableDiscoveryClient 33 | 并注入 DiscoveryClientRouteDefinitionLocator 34 | application.xml: 35 | spring-main-allow-bean-definition-overriding: true (相同名称注入允许覆盖) 36 | spring.application.name:SpringCloud-consul-gateway (设置应用名称必须) 37 | bootstrap.yml 中配置 consul(比application先加载) 38 | prefer-ip-address: true (使用ip注册,有些网络会出现用主机名来获取注册的问题) 39 | (2)fp-commons jar公用 40 | 41 | pom.xml: 42 | 引入依赖文件;添加一些公用方法 43 | (3)fp-authorization-server 44 | 45 | (git中提交了一个至简版本的OAuth2认证中心,只有token生成,没有资源保护以及4种获取token方式(password、authorization_code、refresh_token、client_credentials)) 46 | 47 | 只需要配置AuthorizationServerConfigurerAdapter 认证服务器 48 | 以及WebSecurityConfigurerAdapter SpringSecurity配置 两个文件,就能实现token生成。 49 | 如果没有需要保护的资源不用ResourceServerConfigurerAdapter 资源服务器配置 50 | 51 | AuthorizationServerConfigurerAdapter 认证适配器有三个主要的方法: 52 | 53 | 1、AuthorizationServerSecurityConfigurer:配置令牌端点(Token Endpoint)的安全约束 54 | 55 | (这里我配置了一个处理请求携带客户端信息是否完整的过滤器) 56 | 57 | 2、ClientDetailsServiceConfigurer:配置客户端详细服务, 客户端的详情在这里进行初始化 58 | 59 | (这里我新建了MyClientDetailsService自定义重写了ClientDetailsService接口的loadClientByClientId方法) 60 | 61 | 客户端数据是通过ClientDetailsService接口来管理的,默认有两种方式分别是 62 | InMemoryClientDetailsServiceBuilder 写入内存 63 | JdbcClientDetailsServiceBuilder 写入和数据库 64 | 65 | 3、AuthorizationServerEndpointsConfigurer:配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services) 66 | 67 | (这里我新建了MyUserDetailsService 自定义重写了UserDetailsService的 loadUserByUsername方法) 68 | 69 | 用户数据是通UserDetailsService接口来管理的,默认有两种凡是分别是 70 | InMemoryUserDetailsManager 71 | JdbcUserDetailsManager(有默认的表结构需要在数据库中新建)两种对用户数据的管理实现方式 72 | 73 | 74 | 基于自己的项目,我们可能需要定制化一些自己的功能: 75 | 76 | 1、请求前客户端信息完整性校验 77 | 对于携带数据不完整的请求,可以直接返回给前端,不需要经过后面的验证 78 | 新建一个ClientDetailsAuthenticationFilter 过滤器,在安全约束中加载到过滤链中 79 | 80 | 2、自定义异常返回 81 | 82 | 默认异常翻译为这种形式: 83 | { 84 | "error": "invalid_grant", 85 | "error_description": "Bad credentials" 86 | } 87 | 我们期望的格式: 88 | { 89 | "code":401, 90 | "msg":"msg" 91 | } 92 | 93 | 94 | 新建MyOAuth2WebResponseExceptionTranslator实现 WebResponseExceptionTranslator接口 95 | 96 | 重写ResponseEntity translate(Exception e)方法; 认证发送的异常在这里捕获,认证发生的异常在这里能捕获到,在这里我们可以将我们的异常信息封装成统一的格式返回即可,这里怎么处理因项目而异,这里我直接复制了DefaultWebResponseExceptionTranslator 实现方法 97 | 98 | 定义自己的OAuth2Exception MyOAuth2Exception 99 | 100 | 定义异常的MyOAuth2Exception的序列化类 MyOAuth2ExceptionJacksonSerializer 101 | 102 | 将定义好的异常处理 加入到授权服务器的 AuthorizationServerEndpointsConfigurer配置中 103 | 104 | 效果: 105 | { 106 | "code": 400, 107 | "msg": "error=\"invalid_request\", error_description=\"Missing grant type\"" 108 | } 109 | 3、无权处理器 110 | 111 | 默认的无权访问返回格式是: 112 | { 113 | "error": "access_denied", 114 | "error_description": "不允许访问" 115 | } 116 | 我们期望的格式是: 117 | { 118 | "code":401, 119 | "msg":"msg" 120 | } 121 | 新建一个MyAccessDeniedHandler实现AccessDeniedHandler设置返回信息 122 | 123 | 加入资源配置 ResourceServerConfigurerAdapter 124 | 125 | http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); 126 | 127 | 4、token失效处理器 128 | 129 | 默认的token无效返回信息是: 130 | { 131 | "error": "invalid_token", 132 | "error_description": "Invalid access token: 78df4214-8e10-46ae-a85b-a8f5247370a" 133 | } 134 | 我们期望的格式是: 135 | { 136 | "code":403, 137 | "msg":"msg" 138 | } 139 | 新建MyTokenExceptionEntryPoint 实现AuthenticationEntryPoint 140 | 在 ResourceServerConfigurerAdapter 中注入 141 | 142 | @Override 143 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 144 | resources.authenticationEntryPoint(tokenExceptionEntryPoint); // token失效处理器 145 | resources.resourceId("auth"); // 设置资源id 通过client的 scope 来判断是否具有资源权限 146 | } 147 | 5、自定义token返回信息 148 | 149 | 默认的token返回格式: 150 | 151 | { 152 | "access_token": "1e93bc23-32c8-428f-a126-8206265e17b2", 153 | "token_type": "bearer", 154 | "refresh_token": "0f083e06-be1b-411f-98b0-72be8f1da8af", 155 | "expires_in": 3599, 156 | "scope": "auth api" 157 | } 158 | 我们期望自定义,例如加上username等: 159 | 160 | { 161 | "access_token": "1e93bc23-32c8-428f-a126-8206265e17b2", 162 | "token_type": "bearer", 163 | "refresh_token": "0f083e06-be1b-411f-98b0-72be8f1da8af", 164 | "expires_in": 3599, 165 | "scope": "auth api", 166 | "username":"username" 167 | } 168 | 169 | 新建自定义token返回MyTokenEnhancer实现TokenEnhancer接口 170 | 在认证服务的defaultTokenServices()中添加MyTokenEnhancer。需要注意的是: 171 | 如果已经生成了一次没有自定义的token信息,需要去redis里删除掉该token才能再次测试结果,不然你的结果一直是错误的,因为token还没过期的话,是不会重新生成的。 172 | 173 | (4)fp-resource-manager 用户信息管理资源服务器 174 | 175 | pom.xml:OAuth2、redis等依赖 176 | 把认证服务器中的 资源配置相关复制到资源项目,稍作调整: 177 | 增加健康检查通过, 178 | 179 | 增加redis注入(重点,不然会取不到token对比一直是token失效; 如果自定义过userDetails,记得把自定义实现的文件也复制一份到资源项目,不然redis反序列化会失败。) 180 | 到此可以使用token进行资源保护。 181 | 182 | 6、根据请求URI拦截权限判断 183 | 一般我们通过@PreAuthorize("hasRole('ROLE_USER')") 注解,以及在HttpSecurity配置权限需求等来控制权限 184 | 在这里,我们基于请求的URI来控制访问权限,并且可以使用注解来控制权限访问。 185 | 首先 自定义一个权限认证MySecurityAccessDecisionManager 继承AccessDecisionManager接口,重写 decide方法, 186 | 并且复制默认权限验证AbstractAccessDecisionManager的剩余两个方法(实现注解控制的重点)。 187 | 用户具有的权限在认证服务器中已经自定义了。 188 | 189 | @Override 190 | public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { 191 | String requestUrl = ((FilterInvocation) object).getRequest().getMethod() + ((FilterInvocation) object).getRequest().getRequestURI(); 192 | // System.out.println("requestUrl>>" + requestUrl); 193 | 194 | // 当前用户所具有的权限 195 | Collection authorities = authentication.getAuthorities(); 196 | // System.out.println("authorities=" + authorities); 197 | for (GrantedAuthority grantedAuthority : authorities) { 198 | if (grantedAuthority.getAuthority().equals(requestUrl)) { 199 | return; 200 | } 201 | if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) { 202 | return; 203 | } 204 | 205 | } 206 | throw new AccessDeniedException("无访问权限"); 207 | } 208 | 这里通过判断匹配通过或者抛出无权异常来判断有无访问权限。 209 | 在资源服务器的资源配置中重写权限判断,加载我们自定义的权限判断 210 | 211 | .withObjectPostProcessor(new ObjectPostProcessor() { // 重写做权限判断 212 | @Override 213 | public O postProcess(O o) { 214 | o.setAccessDecisionManager(accessDecisionManager); // 权限判断 215 | return o; 216 | } 217 | }) 218 | 6、1 优化6的权限判断 219 | 先增加一级获取uri然后判断uri需要什么权限,可以多个并且的权限 等等然后 在经过权限判断器进行拦截判断 220 | 新建自定义的url权限判断MyFilterInvocationSecurityMetadataSource 实现FilterInvocationSecurityMetadataSource 221 | private AntPathMatcher antPathMatcher = new AntPathMatcher(); // 模糊匹配 如何 auth/** auth/auth 222 | 223 | @Override 224 | public Collection getAttributes(Object object) throws IllegalArgumentException { 225 | Set set = new HashSet<>(); 226 | 227 | String requestUrl = ((FilterInvocation) object).getRequest().getMethod() + ((FilterInvocation) object).getRequest().getRequestURI(); 228 | System.out.println("requestUrl >> " + requestUrl); 229 | 230 | // 这里获取对比数据可以从数据库或者内存 redis等等地方获取 目前先写死后面优化 231 | String url = "GET/auth/**"; 232 | if (antPathMatcher.match(url, requestUrl)) { 233 | SecurityConfig securityConfig = new SecurityConfig("ROLE_ADMIN"); 234 | set.add(securityConfig); 235 | } 236 | if (ObjectUtils.isEmpty(set)) { 237 | return SecurityConfig.createList("ROLE_LOGIN"); 238 | } 239 | return set; 240 | } 241 | 修改原来的MySecurityAccessDecisionManager,从获取到url 改成获取到需要什么权限。其他判断不变 242 | 把MyFilterInvocationSecurityMetadataSource 注册到重写方法 243 | 244 | .withObjectPostProcessor(new ObjectPostProcessor() { // 重写做权限判断 245 | @Override 246 | public O postProcess(O o) { 247 | o.setSecurityMetadataSource(filterInvocationSecurityMetadataSource); // 请求需要权限 248 | o.setAccessDecisionManager(accessDecisionManager); // 权限判断 249 | return o; 250 | } 251 | }) 252 | 253 | 7、登录登出自定义 254 | 255 | 登出自定义:登出相当于使token失效,我们只需要携带access_token 请求 ConsumerTokenServices(默认自带的注销接口)即可,请求后旧的token即不可用。 256 | 257 | @DeleteMapping("/logout") 258 | public ResponseVo logout(String accessToken) { 259 | if (consumerTokenServices.revokeToken(accessToken)) { 260 | return new ResponseVo(200, "登出成功"); 261 | } else { 262 | return new ResponseVo(500, "登出失败"); 263 | } 264 | } 265 | 登录自定义:默认的token请求地址是“oauth/token”,我们可以在认证服务配置的 AuthorizationServerEndpointsConfigurer配置中自定义的请求地址。 266 | 我们还可以封装一层自己的请求,然后在请求token之前做一些自己的处理。我这里使用了获取需要请求token的信息,然后在java端使用RestTemplate来调用生成token地址 267 | 的方式来获取token,我可以在调用之前做一些其他处理,如验证码校验等等。 268 | 具体看TokenController文件。 269 | 270 | 7、1登录优化-增加验证码 271 | 272 | 登录设置验证码,验证码有效期为1分钟,登录成功后或者到达最大时间后验证码即失效。验证码以用户名_code 的关键字保存在redis中,并设置失效时间 273 | 用户名+验证码匹配通过后才进行下一步的token生成,生成token后,即删除验证码。 274 | 275 | 1.生成带用户名的code 存入redis 设置过期时间 276 | 2.生成token前对比验证码。 277 | 278 | 8、其他方式实现用户名密码登录以及手机号码登录 279 | 手机验证码登录 280 | 新建MyAuthenticationToken 自定义AbstractAuthenticationToken 281 | 282 | 新建 MyPhoneAuthenticationToken(手机验证码登录用) 继承 MyAuthenticationToken 283 | 284 | 新建MyAbstractUserDetailsAuthenticationProvider 抽象类 实现AuthenticationProvider 285 | 286 | 新建 MyPhoneAuthenticationProvider(手机验证码登录 )继承 MyAbstractUserDetailsAuthenticationProvider ,在这里使用MyPhoneAuthenticationToken,注入参数 287 | 288 | 这里负责手机验证码的校验。在这里设置各种错误信息 (在MyLoginAuthFailureHandler 登录失败处理器中处理异常返回信息) 289 | 290 | 修改MyUserDetailsService,改为抽象类,使用模板方法模式: protected abstract AuthUser getUser(String var1); 来获取不同数据来源 291 | 292 | 新建MyUsernameUserDetailsService继承 MyUsernameUserDetailsService 该方法为原来的登录提供数据 293 | 294 | 新建MyPhoneUserDetailsService 继承MyUsernameUserDetailsService 该方法为新的手机验证码登录提供数据。 295 | 296 | 新建MyLoginAuthSuccessHandler 登录成功处理器,该方法用于验证client信息 并返回token信息。 297 | 298 | 新建MyPhoneLoginAuthenticationFilter 手机验证码登录过滤器,拦截登录的url,进行数据注入到MyPhoneAuthenticationToken。 299 | 300 | 修改 MySecurityOAuth2Config ,因为修改了 MyUserDetailsService 接口,无法为原来的登录方式提供数据,所以改为MyUsernameUserDetailsService来提供数据 301 | 302 | 重点 修改MySecurityConfig 配置,装配 两个数据接口,装配 登录成功处理器 装配配置,以及把MyPhoneLoginAuthenticationFilter加入到过滤链。 303 | 304 | 手机验证码模式登录这里完成,用户名密码登录可以参照该流程自行完成 305 | 306 | 8、1 优化自定义异常返回格式, 增加登录失败处理器,返回失败异常 307 | 308 | 9、 swagger 集成 OAuth2 309 | 310 | pom.xml增加 swagger依赖 311 | application中增加swagger的配置 312 | 增加配置文件 SwaggerConfig 313 | 有两种模式 注解掉的是提交增加一个Authorization 提交token框的方式 314 | 方式二:增加token登录框采用登录的方式进行token校验。 315 | Swagger 配置登录相关 application配置 登录url 316 | MySecurityResourceServerConfig 放行 317 | 318 | 测试地址:http://192.168.3.14:8001/manager/swagger-ui.html#/ 319 | 320 | 10、Feign 权限处理 321 | 322 | 新建一个fp-resource-feign服务 323 | pom.xml增加Feign的依赖 324 | Feign 有一个RequestInterceptor接口,对该接口做一些简单的实现,FeignConfig,对请求增加token信息实现授权调用服务接口。 325 | 326 | -------------------------------------------------------------------------------- /fp-authorization-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | SpringCloud-OAuth2-SpringSecurity-Frame 7 | com.wwz.frame 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | fp-authorization-server 13 | OAuth2认证服务项目 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | 19 | 20 | org.springframework.cloud 21 | spring-cloud-starter-oauth2 22 | 23 | 24 | org.springframework.cloud 25 | spring-cloud-starter-consul-discovery 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-data-redis 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | 35 | 36 | com.alibaba 37 | fastjson 38 | 39 | 40 | com.alibaba 41 | druid 42 | 43 | 44 | mysql 45 | mysql-connector-java 46 | 47 | 48 | org.mybatis.spring.boot 49 | mybatis-spring-boot-starter 50 | 51 | 52 | com.wwz.frame 53 | fp-commons 54 | 1.0-SNAPSHOT 55 | 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-maven-plugin 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/AuthorizationServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | 8 | @SpringBootApplication 9 | @EnableDiscoveryClient 10 | @MapperScan("com.wwz.frame.mapper") 11 | public class AuthorizationServerApplication { 12 | public static void main(String[] args) { 13 | SpringApplication.run(AuthorizationServerApplication.class, args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/config/MyAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import com.wwz.frame.common.HttpUtilsResultVO; 4 | import com.wwz.frame.common.ResponseVo; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.security.web.access.AccessDeniedHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | 14 | /** 15 | * @Description 无权访问处理器 16 | * @Author wwz 17 | * @Date 2019/07/30 18 | * @Param 19 | * @Return 20 | */ 21 | @Component 22 | public class MyAccessDeniedHandler implements AccessDeniedHandler { 23 | /** 24 | * Handles an access denied failure. 25 | * 26 | * @param request that resulted in an AccessDeniedException 27 | * @param response so that the user agent can be advised of the failure 28 | * @param accessDeniedException that caused the invocation 29 | * @throws IOException in the event of an IOException 30 | * @throws ServletException in the event of a ServletException 31 | */ 32 | @Override 33 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { 34 | ResponseVo resultVo = new ResponseVo(); 35 | resultVo.setMessage("无权访问!"); 36 | resultVo.setCode(403); 37 | HttpUtilsResultVO.writerError(resultVo, response); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/config/MyLoginAuthFailureHandler.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import com.wwz.frame.common.HttpUtilsResultVO; 4 | import com.wwz.frame.common.ResponseVo; 5 | import org.springframework.security.core.AuthenticationException; 6 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | 14 | /** 15 | * @Description 登录失败处理器 16 | * @Author wwz 17 | * @Date 2019/08/05 18 | * @Param 19 | * @Return 20 | */ 21 | @Component 22 | public class MyLoginAuthFailureHandler implements AuthenticationFailureHandler { 23 | @Override 24 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { 25 | ResponseVo responseVo = new ResponseVo(); 26 | responseVo.setCode(401); 27 | responseVo.setMessage(exception.getMessage()); 28 | responseVo.setData("path:"+request.getRequestURI()); 29 | response.setStatus(200); 30 | HttpUtilsResultVO.writerError(responseVo, response); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/config/MyLoginAuthSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.wwz.frame.service.MyClientDetailsService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 11 | import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException; 12 | import org.springframework.security.oauth2.provider.ClientDetails; 13 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 14 | import org.springframework.security.oauth2.provider.OAuth2Request; 15 | import org.springframework.security.oauth2.provider.TokenRequest; 16 | import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; 17 | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; 18 | import org.springframework.stereotype.Component; 19 | 20 | import javax.servlet.ServletException; 21 | import javax.servlet.http.HttpServletRequest; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | import java.util.Base64; 25 | 26 | /** 27 | * @Description 登录成功处理器 28 | * @Author wwz 29 | * @Date 2019/08/04 30 | * @Param 31 | * @Return 32 | */ 33 | @Component 34 | public class MyLoginAuthSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { 35 | 36 | @Autowired 37 | private MyClientDetailsService clientDetailsService; 38 | 39 | @Autowired 40 | private AuthorizationServerTokenServices authorizationServerTokenServices; 41 | 42 | @Bean 43 | public MyClientDetailsService clientDetailsService(){ 44 | return new MyClientDetailsService(); 45 | } 46 | 47 | @Bean 48 | public PasswordEncoder passwordEncoder() { 49 | return new BCryptPasswordEncoder(); 50 | } 51 | 52 | @Override 53 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 54 | String header = request.getHeader("Authorization"); 55 | if (header == null && !header.startsWith("Basic")) { 56 | throw new UnapprovedClientAuthenticationException("请求投中无client信息"); 57 | } 58 | String tmp = header.substring(6); 59 | String defaultClientDetails = new String(Base64.getDecoder().decode(tmp)); 60 | 61 | String[] clientArrays = defaultClientDetails.split(":"); 62 | String clientId = clientArrays[0].trim(); 63 | String clientSecret = clientArrays[1].trim(); 64 | 65 | 66 | ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId); 67 | 68 | if (clientDetails == null) { 69 | throw new UnapprovedClientAuthenticationException("clientId 不存在" + clientId); 70 | //判断 方言 是否一致 71 | } else if (!passwordEncoder().matches(clientSecret, clientDetails.getClientSecret())) { 72 | throw new UnapprovedClientAuthenticationException("clientSecret 不匹配" + clientId); 73 | } 74 | TokenRequest tokenRequest = new TokenRequest(null, clientId, clientDetails.getScope(), "custom"); 75 | 76 | OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails); 77 | 78 | OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication); 79 | 80 | OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication); 81 | 82 | response.setContentType("application/json;charset=UTF-8"); 83 | response.getWriter().write(JSONObject.toJSONString(token)); 84 | } 85 | } -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/config/MySecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import com.wwz.frame.filter.MyPhoneLoginAuthenticationFilter; 4 | import com.wwz.frame.provider.MyPhoneAuthenticationProvider; 5 | import com.wwz.frame.service.MyPhoneUserDetailsService; 6 | import com.wwz.frame.service.MyUsernameUserDetailsService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.core.annotation.Order; 11 | import org.springframework.security.authentication.AuthenticationManager; 12 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 13 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 14 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 15 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 16 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 17 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 18 | import org.springframework.security.crypto.password.PasswordEncoder; 19 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 20 | 21 | /** 22 | * @Description security 配置 23 | * ResourceServerConfigurerAdapter 是比WebSecurityConfigurerAdapter 的优先级低的 24 | * @Author wwz 25 | * @Date 2019/07/28 26 | * @Param 27 | * @Return 28 | */ 29 | @Configuration 30 | @EnableWebSecurity 31 | @Order(2) // WebSecurityConfigurerAdapter 默认为100 这里配置为2设置比资源认证器高 32 | public class MySecurityConfig extends WebSecurityConfigurerAdapter { 33 | 34 | // 自定义用户验证数据 35 | @Autowired 36 | private MyUsernameUserDetailsService myUsernameUserDetailsService; 37 | 38 | @Autowired 39 | private MyPhoneUserDetailsService myPhoneUserDetailsService; 40 | 41 | 42 | // 装配登录成功处理器 生成token用 通用, 下方配置的时候不能用new 的形式加入 不然里面的接口注入会报空指针 43 | @Autowired 44 | private MyLoginAuthSuccessHandler myLoginAuthSuccessHandler; 45 | 46 | @Autowired 47 | private MyLoginAuthFailureHandler myLoginAuthFailureHandler; // 配置登录失败处理器 48 | 49 | // 加密方式 50 | @Bean 51 | public PasswordEncoder passwordEncoder() { 52 | return new BCryptPasswordEncoder(); 53 | } 54 | 55 | // 验证器加载 56 | @Override 57 | @Bean 58 | public AuthenticationManager authenticationManagerBean() throws Exception { 59 | return super.authenticationManagerBean(); 60 | } 61 | 62 | @Override 63 | protected void configure(HttpSecurity http) throws Exception { 64 | http 65 | .addFilterBefore(getPhoneLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) 66 | // 匹配oauth相关,匹配健康,匹配默认登录登出 在httpSecurity处理,,其他到ResourceServerConfigurerAdapter OAuth2处理 1 67 | .requestMatchers().antMatchers("/oauth/**", "/actuator/health", "/client/login","/client/getCode","/token/phoneLogin") 68 | .and() 69 | // 匹配的全部无条件通过 permitAll 2 70 | .authorizeRequests().antMatchers("/oauth/**", "/actuator/health", "/client/login","/client/getCode","/token/phoneLogin").permitAll() 71 | // 匹配条件1的 并且不再条件2通过范围内的其他url全部需要验证登录 72 | .and().authorizeRequests().anyRequest().authenticated() 73 | // 启用登录验证 74 | .and().formLogin().permitAll(); 75 | // 不启用 跨站请求伪造 默认为启用, 需要启用的话得在form表单中生成一个_csrf 76 | http.csrf().disable(); 77 | } 78 | 79 | @Override 80 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 81 | auth.authenticationProvider(daoAuthenticationProvider()); 82 | auth.authenticationProvider(myPhoneAuthenticationProvider()); 83 | } 84 | 85 | @Bean 86 | public DaoAuthenticationProvider daoAuthenticationProvider() { 87 | DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); 88 | // 设置userDetailsService 89 | provider.setUserDetailsService(myUsernameUserDetailsService); 90 | // 禁止隐藏用户未找到异常 91 | provider.setHideUserNotFoundExceptions(false); 92 | // 使用BCrypt进行密码的hash 93 | provider.setPasswordEncoder(passwordEncoder()); 94 | return provider; 95 | } 96 | 97 | @Bean 98 | public MyPhoneAuthenticationProvider myPhoneAuthenticationProvider() { 99 | MyPhoneAuthenticationProvider provider = new MyPhoneAuthenticationProvider(); 100 | provider.setUserDetailsService(myPhoneUserDetailsService); 101 | provider.setHideUserNotFoundExceptions(false); 102 | return provider; 103 | } 104 | 105 | /** 106 | * 手机验证码登陆过滤器 107 | */ 108 | @Bean 109 | public MyPhoneLoginAuthenticationFilter getPhoneLoginAuthenticationFilter() { 110 | MyPhoneLoginAuthenticationFilter filter = new MyPhoneLoginAuthenticationFilter(); 111 | try { 112 | filter.setAuthenticationManager(this.authenticationManagerBean()); 113 | } catch (Exception e) { 114 | e.printStackTrace(); 115 | } 116 | filter.setAuthenticationSuccessHandler(myLoginAuthSuccessHandler); 117 | filter.setAuthenticationFailureHandler(myLoginAuthFailureHandler); 118 | return filter; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/config/MySecurityOAuth2Config.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import com.wwz.frame.exception.MyOAuth2WebResponseExceptionTranslator; 4 | import com.wwz.frame.filter.ClientDetailsAuthenticationFilter; 5 | import com.wwz.frame.service.MyClientDetailsService; 6 | import com.wwz.frame.service.MyUsernameUserDetailsService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.Primary; 11 | import org.springframework.data.redis.connection.RedisConnectionFactory; 12 | import org.springframework.security.authentication.AuthenticationManager; 13 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 14 | import org.springframework.security.crypto.password.PasswordEncoder; 15 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 16 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 17 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 18 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; 19 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 20 | import org.springframework.security.oauth2.provider.token.DefaultTokenServices; 21 | import org.springframework.security.oauth2.provider.token.TokenEnhancer; 22 | import org.springframework.security.oauth2.provider.token.TokenStore; 23 | import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; 24 | 25 | /** 26 | * @Description OAuth2认证服务配置 27 | * @Author wwz 28 | * @Date 2019/07/28 29 | * @Param 30 | * @Return 31 | */ 32 | @Configuration 33 | @EnableAuthorizationServer 34 | public class MySecurityOAuth2Config extends AuthorizationServerConfigurerAdapter { 35 | @Autowired 36 | private AuthenticationManager authenticationManager; // 认证方法入口 37 | 38 | @Autowired 39 | private RedisConnectionFactory connectionFactory; // redis连接工厂 40 | 41 | @Autowired 42 | private MyUsernameUserDetailsService userDetailsService; // 自定义用户验证数据 43 | 44 | @Autowired 45 | private MyClientDetailsService clientDetailsService; // 自定义客户端数据 46 | @Autowired 47 | private ClientDetailsAuthenticationFilter clientDetailsAuthenticationFilter; // 客户端认证之前的过滤器 48 | 49 | @Autowired 50 | private MyOAuth2WebResponseExceptionTranslator webResponseExceptionTranslator; // 自定义返回异常格式 51 | 52 | // 加密方式 53 | @Bean 54 | public PasswordEncoder passwordEncoder() { 55 | return new BCryptPasswordEncoder(); 56 | } 57 | 58 | /*** 59 | * 设置token用redis保存 60 | */ 61 | @Bean 62 | public TokenStore tokenStore() { 63 | //token保存在redis中(也可以保存在数据库、内存中new InMemoryTokenStore()、或者jwt;)。 64 | //如果保存在中间件(数据库、Redis),那么资源服务器与认证服务器可以不在同一个工程中。 65 | //注意:如果不保存access_token,则没法通过access_token取得用户信息 66 | RedisTokenStore redis = new RedisTokenStore(connectionFactory); 67 | return redis; 68 | } 69 | 70 | /** 71 | * 配置令牌端点(Token Endpoint)的安全约束 72 | */ 73 | @Override 74 | public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { 75 | // 加载client的 获取接口 76 | clientDetailsAuthenticationFilter.setClientDetailsService(clientDetailsService); 77 | // 客户端认证之前的过滤器 78 | oauthServer.addTokenEndpointAuthenticationFilter(clientDetailsAuthenticationFilter); 79 | oauthServer 80 | .tokenKeyAccess("permitAll()") 81 | .checkTokenAccess("isAuthenticated()") 82 | .allowFormAuthenticationForClients(); // 允许表单登录 83 | } 84 | 85 | /** 86 | * 配置 oauth_client_details【client_id和client_secret等】信息的认证【检查ClientDetails的合法性】服务 87 | * 设置 认证信息的来源:数据库,内存,也可以自己实现ClientDetailsService的loadClientByClientId 方法自定义数据源 88 | * 自动注入:ClientDetailsService的实现类 JdbcClientDetailsService (检查 ClientDetails 对象) 89 | * 这个方法主要是用于校验注册的第三方客户端的信息,可以存储在数据库中,默认方式是存储在内存中 90 | */ 91 | @Override 92 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 93 | // 设置从默认自带数据连接方式取 94 | clients.withClientDetails(clientDetailsService); 95 | // clients.inMemory() // 使用in-memory存储 96 | // .withClient("client_name") // client_id 97 | // .secret(passwordEncoder().encode("111")) // client_secret 98 | // .redirectUris("http://localhost:8001") 99 | // // 该client允许的授权类型 100 | // .authorizedGrantTypes("password", "authorization_code", "refresh_token", "client_credentials") 101 | // .scopes("app", "app1", "app3"); // 允许的授权范围 102 | } 103 | 104 | /** 105 | * 配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services) 106 | */ 107 | @Override 108 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 109 | // endpoints.pathMapping("/oauth/token","/token/login"); 设置token生成请求地址 110 | endpoints 111 | .tokenStore(tokenStore()) // 配置token存储 112 | .userDetailsService(userDetailsService) // 配置自定义的用户权限数据,不配置会导致token无法刷新 113 | .authenticationManager(authenticationManager) 114 | .tokenServices(defaultTokenServices())// 加载token配置 115 | .exceptionTranslator(webResponseExceptionTranslator); // 自定义异常返回 116 | } 117 | 118 | /** 119 | * 把认证的token保存到redis 120 | *

注意,自定义TokenServices的时候,需要设置@Primary,否则报错,

121 | * 自定义的token 122 | * 认证的token是存到redis里的 若ClientDetails中设定了有效时间则以设定值为准 123 | */ 124 | @Primary 125 | @Bean 126 | public DefaultTokenServices defaultTokenServices() { 127 | DefaultTokenServices tokenServices = new DefaultTokenServices(); 128 | tokenServices.setTokenStore(tokenStore()); 129 | tokenServices.setSupportRefreshToken(true); 130 | tokenServices.setTokenEnhancer(tokenEnhancer()); // token自定义 131 | tokenServices.setClientDetailsService(clientDetailsService); 132 | tokenServices.setAccessTokenValiditySeconds(60 * 60 * 12); // token有效期自定义设置,默认12小时 133 | tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7); // refresh_token默认30天 134 | return tokenServices; 135 | } 136 | @Bean 137 | public TokenEnhancer tokenEnhancer() { 138 | return new MyTokenEnhancer(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/config/MySecurityResourceServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.core.annotation.Order; 5 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.http.SessionCreationPolicy; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 10 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 11 | 12 | import javax.annotation.Resource; 13 | import javax.servlet.http.HttpServletResponse; 14 | 15 | /** 16 | * @Description 资源认证 17 | * @Author wwz 18 | * @Date 2019/07/30 19 | * @Param 20 | * @Return 21 | */ 22 | @Configuration 23 | @EnableResourceServer 24 | @EnableGlobalMethodSecurity(prePostEnabled = true) // 启用注解权限配置 25 | @Order(3) 26 | public class MySecurityResourceServerConfig extends ResourceServerConfigurerAdapter { 27 | @Resource 28 | private MyAccessDeniedHandler accessDeniedHandler; // 无权访问处理器 29 | 30 | @Resource 31 | private MyTokenExceptionEntryPoint tokenExceptionEntryPoint; // token失效处理器 32 | 33 | @Override 34 | public void configure(HttpSecurity http) throws Exception { 35 | http 36 | .csrf().disable() 37 | .exceptionHandling() 38 | .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED)) 39 | .and() 40 | .requestMatchers().antMatchers("/**") // .requestMatchers().antMatchers(...),表示对资源进行保护,也就是说,在访问前要进行OAuth认证。 41 | .and() 42 | .authorizeRequests() 43 | .antMatchers("/**").authenticated() 44 | .and() 45 | .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 另外,如果不设置,那么在通过浏览器访问被保护的任何资源时,每次是不同的SessionID,并且将每次请求的历史都记录在OAuth2Authentication的details的中 46 | .and() 47 | .httpBasic(); 48 | http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); 49 | } 50 | @Override 51 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 52 | resources.authenticationEntryPoint(tokenExceptionEntryPoint); // token失效处理器 53 | resources.resourceId("auth"); // 设置资源id 通过client的 resource_ids 来判断是否具有资源权限 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/config/MyTokenEnhancer.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import com.wwz.frame.service.MyUserDetails; 4 | import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; 5 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 6 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 7 | import org.springframework.security.oauth2.provider.token.TokenEnhancer; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * @Description 自定义token返回值 14 | * @Author wwz 15 | * @Date 2019/07/31 16 | * @Param 17 | * @Return 18 | */ 19 | public class MyTokenEnhancer implements TokenEnhancer { 20 | @Override 21 | public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { 22 | MyUserDetails user = (MyUserDetails) authentication.getPrincipal(); 23 | final Map additionalInfo = new HashMap<>(); 24 | additionalInfo.put("username", user.getUsername()); 25 | ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); 26 | return accessToken; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/config/MyTokenExceptionEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import com.wwz.frame.common.HttpUtilsResultVO; 4 | import com.wwz.frame.common.ResponseVo; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.security.core.AuthenticationException; 7 | import org.springframework.security.web.AuthenticationEntryPoint; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | 15 | /** 16 | * @Description 无效Token返回处理器 17 | * @Author wwz 18 | * @Date 2019/07/30 19 | * @Param 20 | * @Return 21 | */ 22 | @Component 23 | public class MyTokenExceptionEntryPoint implements AuthenticationEntryPoint { 24 | /** 25 | * Commences an authentication scheme. 26 | *

27 | * ExceptionTranslationFilter will populate the HttpSession 28 | * attribute named 29 | * AbstractAuthenticationProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY 30 | * with the requested target URL before calling this method. 31 | *

32 | * Implementations should modify the headers on the ServletResponse as 33 | * necessary to commence the authentication process. 34 | * 35 | * @param request that resulted in an AuthenticationException 36 | * @param response so that the user agent can begin authentication 37 | * @param authException that caused the invocation 38 | */ 39 | @Override 40 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 41 | // Throwable cause = authException.getCause(); 如果需要具体判断类型的话,从这里取类型 42 | response.setStatus(HttpStatus.OK.value()); 43 | response.setHeader("Content-Type", "application/json;charset=UTF-8"); 44 | try { 45 | HttpUtilsResultVO.writerError(new ResponseVo(401, authException.getMessage()), response); 46 | // response.getWriter().write(new ResponseVo(401, authException.getMessage()), response); 47 | } catch (IOException e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/config/RestTemplateClientConfig.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.apache.http.config.Registry; 5 | import org.apache.http.config.RegistryBuilder; 6 | import org.apache.http.conn.socket.ConnectionSocketFactory; 7 | import org.apache.http.conn.socket.PlainConnectionSocketFactory; 8 | import org.apache.http.conn.ssl.NoopHostnameVerifier; 9 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; 10 | import org.apache.http.conn.ssl.TrustStrategy; 11 | import org.apache.http.impl.client.CloseableHttpClient; 12 | import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; 13 | import org.apache.http.impl.client.HttpClientBuilder; 14 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 15 | import org.apache.http.ssl.SSLContextBuilder; 16 | import org.springframework.context.annotation.Bean; 17 | import org.springframework.context.annotation.Configuration; 18 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; 19 | import org.springframework.web.client.DefaultResponseErrorHandler; 20 | import org.springframework.web.client.RestTemplate; 21 | 22 | import javax.net.ssl.HostnameVerifier; 23 | import javax.net.ssl.SSLContext; 24 | import java.security.KeyManagementException; 25 | import java.security.KeyStoreException; 26 | import java.security.NoSuchAlgorithmException; 27 | import java.security.cert.X509Certificate; 28 | 29 | /** 30 | * @Description RestTemplate 连接池配置 31 | * @Author wwz 32 | * @Date 2019/08/02 33 | * @Param 34 | * @Return 35 | */ 36 | @Configuration 37 | @Slf4j 38 | public class RestTemplateClientConfig { 39 | 40 | @Bean 41 | public RestTemplate restTemplate() { 42 | RestTemplate restTemplate = new RestTemplate(); 43 | restTemplate.setRequestFactory(clientHttpRequestFactory()); 44 | restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); 45 | return restTemplate; 46 | } 47 | 48 | @Bean 49 | public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() { 50 | try { 51 | HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); 52 | SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { 53 | public boolean isTrusted(X509Certificate[] arg0, String arg1) { 54 | return true; 55 | } 56 | }).build(); 57 | httpClientBuilder.setSSLContext(sslContext); 58 | HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; 59 | SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); 60 | Registry socketFactoryRegistry = RegistryBuilder.create() 61 | .register("http", PlainConnectionSocketFactory.getSocketFactory()) 62 | .register("https", sslConnectionSocketFactory).build();// 注册http和https请求 63 | // 开始设置连接池 64 | PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); 65 | poolingHttpClientConnectionManager.setMaxTotal(500); // 最大连接数500 66 | poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); // 同路由并发数100 67 | httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); 68 | httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 重试次数 69 | CloseableHttpClient httpClient = httpClientBuilder.build(); 70 | HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // httpClient连接配置 71 | clientHttpRequestFactory.setConnectTimeout(20000); // 连接超时 72 | clientHttpRequestFactory.setReadTimeout(30000); // 数据读取超时时间 73 | clientHttpRequestFactory.setConnectionRequestTimeout(20000); // 连接不够用的等待时间 74 | return clientHttpRequestFactory; 75 | } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { 76 | log.error("初始化HTTP连接池出错", e); 77 | } 78 | return null; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/controller/TokenController.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.controller; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.wwz.frame.common.LinkStringUtil; 5 | import com.wwz.frame.common.ResponseVo; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.http.HttpEntity; 9 | import org.springframework.http.HttpHeaders; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.security.oauth2.provider.token.ConsumerTokenServices; 13 | import org.springframework.web.bind.annotation.DeleteMapping; 14 | import org.springframework.web.bind.annotation.PostMapping; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | import org.springframework.web.client.RestTemplate; 18 | 19 | import javax.servlet.http.HttpServletRequest; 20 | import java.io.UnsupportedEncodingException; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | import java.util.concurrent.TimeUnit; 24 | 25 | /** 26 | * @Description 登录登出模块 27 | * @Author wwz 28 | * @Date 2019/08/02 29 | * @Param 30 | * @Return 31 | */ 32 | @RestController 33 | @RequestMapping("/client") 34 | public class TokenController { 35 | @Autowired 36 | private ConsumerTokenServices consumerTokenServices; 37 | 38 | @Autowired 39 | RestTemplate restTemplate; 40 | 41 | @Autowired 42 | private RedisTemplate redisTemplate; 43 | 44 | @DeleteMapping("/logout") 45 | public ResponseVo logout(String accessToken) { 46 | if (consumerTokenServices.revokeToken(accessToken)) { 47 | return new ResponseVo(200, "登出成功"); 48 | } else { 49 | return new ResponseVo(500, "登出失败"); 50 | } 51 | } 52 | 53 | @PostMapping("/login") 54 | public ResponseVo login(HttpServletRequest request) throws UnsupportedEncodingException { 55 | String header = request.getHeader("Authorization"); 56 | if (header == null && !header.startsWith("Basic")) { 57 | return new ResponseVo(400, "请求头中缺少参数"); 58 | } 59 | String code = request.getParameter("code"); 60 | String username = request.getParameter("username"); 61 | 62 | if(code==null){ 63 | return new ResponseVo(500,"验证码缺失"); 64 | } 65 | String old_code =redisTemplate.opsForValue().get(username+"_code"); 66 | 67 | if(old_code==null){ 68 | return new ResponseVo(500,"验证码不存在或者已经过期"); 69 | } 70 | if(!code.equals(old_code)){ 71 | return new ResponseVo(500,"验证码错误"); 72 | } 73 | 74 | 75 | String url = "http://" + request.getRemoteAddr() + ":" + request.getServerPort() + "/oauth/token"; 76 | 77 | Map map = new HashMap<>(); 78 | map.put("grant_type", "password"); 79 | map.put("username", username); 80 | map.put("password", request.getParameter("password")); 81 | 82 | HttpHeaders headers = new HttpHeaders(); 83 | headers.set("Authorization", header); 84 | headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // 必须该模式,不然请求端无法取到 grant_type 85 | 86 | HttpEntity httpEntity = new HttpEntity<>(headers); 87 | 88 | ResponseEntity response = restTemplate.postForEntity(url + "?" + LinkStringUtil.createLinkStringByGet(map), httpEntity, String.class); 89 | 90 | if (response.getStatusCodeValue() == 200) { 91 | return new ResponseVo(200, "登录成功", JSONObject.parseObject(response.getBody())); 92 | } else { 93 | return new ResponseVo(500, "登录失败"); 94 | } 95 | } 96 | 97 | @PostMapping("/getCode") 98 | public String getCode(String username) { 99 | String code = String.valueOf(Math.random() * 100); 100 | redisTemplate.opsForValue().set(username + "_code", code, 60, TimeUnit.SECONDS); 101 | return "code is " + code; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/exception/MyOAuth2Exception.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.exception; 2 | 3 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 4 | import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; 5 | 6 | /** 7 | * @Description 异常处理类 8 | * @Author wwz 9 | * @Date 2019/07/30 10 | * @Param 11 | * @Return 12 | */ 13 | @JsonSerialize(using = MyOAuthExceptionJacksonSerializer.class) 14 | public class MyOAuth2Exception extends OAuth2Exception { 15 | public MyOAuth2Exception(String msg, Throwable t) { 16 | super(msg, t); 17 | 18 | } 19 | public MyOAuth2Exception(String msg) { 20 | super(msg); 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/exception/MyOAuth2WebResponseExceptionTranslator.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.exception; 2 | 3 | import org.springframework.http.ResponseEntity; 4 | import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; 5 | import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * @Description WebResponseExceptionTranslator 10 | * @Author wwz 11 | * @Date 2019/07/30 12 | * @Param 13 | * @Return 14 | */ 15 | @Component("MyOAuth2WebResponseExceptionTranslator") 16 | public class MyOAuth2WebResponseExceptionTranslator implements WebResponseExceptionTranslator { 17 | 18 | @Override 19 | public ResponseEntity translate(Exception e) { 20 | OAuth2Exception oAuth2Exception = (OAuth2Exception) e; 21 | return ResponseEntity.status(oAuth2Exception.getHttpErrorCode()) 22 | .body(new MyOAuth2Exception(oAuth2Exception.getMessage())); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/exception/MyOAuthExceptionJacksonSerializer.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.exception; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.SerializerProvider; 5 | import com.fasterxml.jackson.databind.ser.std.StdSerializer; 6 | import org.springframework.web.context.request.RequestContextHolder; 7 | import org.springframework.web.context.request.ServletRequestAttributes; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import java.io.IOException; 11 | import java.util.Map; 12 | 13 | /** 14 | * @Description 定义异常MyOAuth2Exception的序列化 15 | * @Author wwz 16 | * @Date 2019/07/11 17 | * @Param 18 | * @Return 19 | */ 20 | public class MyOAuthExceptionJacksonSerializer extends StdSerializer { 21 | 22 | protected MyOAuthExceptionJacksonSerializer() { 23 | super(MyOAuth2Exception.class); 24 | } 25 | 26 | @Override 27 | public void serialize(MyOAuth2Exception value, JsonGenerator jgen, SerializerProvider serializerProvider) throws IOException { 28 | HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 29 | jgen.writeStartObject(); 30 | jgen.writeObjectField("code", value.getHttpErrorCode()); 31 | jgen.writeStringField("msg", value.getSummary()); 32 | // jgen.writeStringField("path",request.getServletPath()); 33 | // jgen.writeStringField("timestamp",String.valueOf(new Date().getTime())); 34 | if(value.getAdditionalInformation()!=null){ 35 | for (Map.Entry entry : value.getAdditionalInformation().entrySet()) { 36 | String key = entry.getKey(); 37 | String add = entry.getValue(); 38 | jgen.writeStringField(key, add); 39 | } 40 | } 41 | jgen.writeEndObject(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/filter/ClientDetailsAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.filter; 2 | 3 | import com.wwz.frame.common.HttpUtilsResultVO; 4 | import com.wwz.frame.common.ResponseVo; 5 | import com.wwz.frame.service.MyClientDetails; 6 | import org.springframework.http.HttpHeaders; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.context.SecurityContextHolder; 11 | import org.springframework.security.oauth2.provider.ClientDetailsService; 12 | import org.springframework.stereotype.Component; 13 | import org.springframework.web.filter.OncePerRequestFilter; 14 | 15 | import javax.servlet.FilterChain; 16 | import javax.servlet.ServletException; 17 | import javax.servlet.http.HttpServletRequest; 18 | import javax.servlet.http.HttpServletResponse; 19 | import java.io.IOException; 20 | import java.util.Base64; 21 | 22 | /** 23 | * @Description 客户端不带完整client处理 24 | * @Author wwz 25 | * @Date 2019/07/30 26 | * @Param 27 | * @Return 28 | */ 29 | @Component 30 | public class ClientDetailsAuthenticationFilter extends OncePerRequestFilter { 31 | 32 | private ClientDetailsService clientDetailsService; 33 | 34 | @Override 35 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 36 | // 只有获取token的时候需要携带携带客户端信息,放过其他 37 | if (!request.getRequestURI().equals("/oauth/token")) { 38 | filterChain.doFilter(request, response); 39 | return; 40 | } 41 | String[] clientDetails = this.isHasClientDetails(request); 42 | 43 | if (clientDetails == null) { 44 | ResponseVo resultVo = new ResponseVo(HttpStatus.UNAUTHORIZED.value(), "请求中未包含客户端信息"); 45 | HttpUtilsResultVO.writerError(resultVo, response); 46 | return; 47 | } 48 | this.handle(request, response, clientDetails, filterChain); 49 | } 50 | private void handle(HttpServletRequest request, HttpServletResponse response, String[] clientDetails, FilterChain filterChain) throws IOException, ServletException { 51 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 52 | 53 | if (authentication != null && authentication.isAuthenticated()) { 54 | filterChain.doFilter(request, response); 55 | return; 56 | } 57 | 58 | 59 | MyClientDetails details = (MyClientDetails) this.getClientDetailsService().loadClientByClientId(clientDetails[0]); 60 | UsernamePasswordAuthenticationToken token = 61 | new UsernamePasswordAuthenticationToken(details.getClientId(), details.getClientSecret(), details.getAuthorities()); 62 | 63 | SecurityContextHolder.getContext().setAuthentication(token); 64 | 65 | 66 | filterChain.doFilter(request, response); 67 | } 68 | /** 69 | * 判断请求头中是否包含client信息,不包含返回null Base64编码 70 | */ 71 | private String[] isHasClientDetails(HttpServletRequest request) { 72 | 73 | String[] params = null; 74 | 75 | String header = request.getHeader(HttpHeaders.AUTHORIZATION); 76 | 77 | if (header != null) { 78 | 79 | String basic = header.substring(0, 5); 80 | 81 | if (basic.toLowerCase().contains("basic")) { 82 | 83 | String tmp = header.substring(6); 84 | String defaultClientDetails = new String(Base64.getDecoder().decode(tmp)); 85 | 86 | String[] clientArrays = defaultClientDetails.split(":"); 87 | 88 | if (clientArrays.length != 2) { 89 | return params; 90 | } else { 91 | params = clientArrays; 92 | } 93 | 94 | } 95 | } 96 | String id = request.getParameter("client_id"); 97 | String secret = request.getParameter("client_secret"); 98 | 99 | if (header == null && id != null) { 100 | params = new String[]{id, secret}; 101 | } 102 | return params; 103 | } 104 | public ClientDetailsService getClientDetailsService() { 105 | return clientDetailsService; 106 | } 107 | 108 | public void setClientDetailsService(ClientDetailsService clientDetailsService) { 109 | this.clientDetailsService = clientDetailsService; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/filter/MyPhoneLoginAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.filter; 2 | 3 | import com.wwz.frame.token.MyPhoneAuthenticationToken; 4 | import org.springframework.security.authentication.AbstractAuthenticationToken; 5 | import org.springframework.security.authentication.AuthenticationServiceException; 6 | import org.springframework.security.core.Authentication; 7 | import org.springframework.security.core.AuthenticationException; 8 | import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; 9 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | 14 | /** 15 | * @Description 手机验证码:post /token/login?type=phoneNumber&phoneNumber=15000000000&phoneCode=1234 16 | * @Author wwz 17 | * @Date 2019/08/04 18 | * @Param 19 | * @Return 20 | */ 21 | public class MyPhoneLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 22 | private static final String PHONE_NUMBER_KEY = "phoneNumber"; // 手机号码 23 | 24 | private static final String PHONE_NUMBER_CODE_KEY = "phoneCode"; // 验证码 25 | 26 | private boolean postOnly = true; 27 | 28 | private static final String LOGIN_URL = "/token/phoneLogin"; 29 | 30 | public MyPhoneLoginAuthenticationFilter() { 31 | super(new AntPathRequestMatcher(LOGIN_URL, "POST")); 32 | } 33 | 34 | 35 | @Override 36 | public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 37 | if (postOnly && !request.getMethod().equals("POST")) { 38 | throw new AuthenticationServiceException( 39 | "Authentication method not supported: " + request.getMethod()); 40 | } 41 | 42 | AbstractAuthenticationToken authRequest; 43 | // 手机验证码登陆 44 | String principal =RequestUtil(request,PHONE_NUMBER_KEY); 45 | String credentials =RequestUtil(request,PHONE_NUMBER_CODE_KEY); 46 | 47 | 48 | 49 | principal = principal.trim(); 50 | authRequest = new MyPhoneAuthenticationToken(principal, credentials); 51 | 52 | // Allow subclasses to set the "details" property 53 | setDetails(request, authRequest); 54 | return this.getAuthenticationManager().authenticate(authRequest); 55 | } 56 | 57 | private void setDetails(HttpServletRequest request, 58 | AbstractAuthenticationToken authRequest) { 59 | authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); 60 | } 61 | 62 | private String RequestUtil(HttpServletRequest request, String parameter) { 63 | String result = request.getParameter(parameter); 64 | return result == null ? "" : result; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/mapper/AuthClientDetailsMapper.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.mapper; 2 | 3 | import com.wwz.frame.entity.AuthClientDetails; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | import org.apache.ibatis.annotations.Select; 7 | 8 | 9 | public interface AuthClientDetailsMapper { 10 | @Select("select *from auth_client_details where client_id = #{clientId}") 11 | AuthClientDetails selectClientDetailsByClientId(@Param("clientId") String clientId); 12 | } 13 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/mapper/AuthPermissionMapper.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.mapper; 2 | 3 | import com.wwz.frame.entity.AuthPermission; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | import org.apache.ibatis.annotations.Select; 7 | 8 | import java.util.List; 9 | 10 | 11 | public interface AuthPermissionMapper { 12 | @Select("select *from auth_permission ap inner join auth_role_permission arp on ap.id= arp.auth_permission_id where arp.auth_role_id =#{authRoleId} ") 13 | List listAuthPermissionsByAuthRoleId(@Param("authRoleId") Integer authRoleId); 14 | } 15 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/mapper/AuthRoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.mapper; 2 | 3 | import com.wwz.frame.entity.AuthRole; 4 | import org.apache.ibatis.annotations.*; 5 | 6 | import java.util.List; 7 | 8 | 9 | public interface AuthRoleMapper { 10 | @Select("select *from auth_role ar inner join auth_user_role aur on ar.id=auth_role_id where aur.auth_user_id=#{authUserId}") 11 | @Results({ 12 | @Result(property = "authPermissions", column = "id", 13 | many = @Many(select = "com.wwz.frame.mapper.AuthPermissionMapper.listAuthPermissionsByAuthRoleId")) 14 | }) 15 | List listAuthRoleByAuthUserId(@Param("authUserId") Integer authUserId); 16 | } 17 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/mapper/AuthUserMapper.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.mapper; 2 | 3 | import com.wwz.frame.entity.AuthUser; 4 | import org.apache.ibatis.annotations.*; 5 | 6 | 7 | public interface AuthUserMapper { 8 | @Select("select *from auth_user where id=#{id}") 9 | @Results({ 10 | @Result(property = "authRoles", column = "id", 11 | many = @Many(select = "com.wwz.frame.mapper.AuthRoleMapper.listAuthRoleByAuthUserId")) 12 | }) 13 | AuthUser selectById(@Param("id") Integer id); 14 | 15 | @Select("select *from auth_user where username=#{username}") 16 | AuthUser selectByUsername(@Param("username") String username); 17 | 18 | @Select("select *from auth_user where phone=#{phone}") 19 | AuthUser selectByPhone(@Param("phone") String phone); 20 | } 21 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/provider/MyAbstractUserDetailsAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.provider; 2 | 3 | import org.apache.commons.logging.Log; 4 | import org.apache.commons.logging.LogFactory; 5 | import org.springframework.beans.factory.InitializingBean; 6 | import org.springframework.context.MessageSource; 7 | import org.springframework.context.MessageSourceAware; 8 | import org.springframework.context.support.MessageSourceAccessor; 9 | import org.springframework.security.authentication.*; 10 | import org.springframework.security.core.Authentication; 11 | import org.springframework.security.core.AuthenticationException; 12 | import org.springframework.security.core.SpringSecurityMessageSource; 13 | import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; 14 | import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper; 15 | import org.springframework.security.core.userdetails.UserCache; 16 | import org.springframework.security.core.userdetails.UserDetails; 17 | import org.springframework.security.core.userdetails.UserDetailsChecker; 18 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 19 | import org.springframework.security.core.userdetails.cache.NullUserCache; 20 | import org.springframework.util.Assert; 21 | 22 | /** 23 | * @Description 自定义AuthenticationProvider 抽象,方便其他扩展 24 | * @Author wwz 25 | * @Date 2019/08/04 26 | * @Param 27 | * @Return 28 | */ 29 | public abstract class MyAbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware { 30 | 31 | protected final Log logger = LogFactory.getLog(this.getClass()); 32 | protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); 33 | private UserCache userCache = new NullUserCache(); 34 | private boolean forcePrincipalAsString = false; 35 | protected boolean hideUserNotFoundExceptions = true; 36 | private UserDetailsChecker preAuthenticationChecks = new MyAbstractUserDetailsAuthenticationProvider.DefaultPreAuthenticationChecks(); 37 | private UserDetailsChecker postAuthenticationChecks = new MyAbstractUserDetailsAuthenticationProvider.DefaultPostAuthenticationChecks(); 38 | private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper(); 39 | 40 | 41 | protected abstract void additionalAuthenticationChecks(UserDetails var1, Authentication var2) throws AuthenticationException; 42 | 43 | public final void afterPropertiesSet() throws Exception { 44 | Assert.notNull(this.userCache, "A user cache must be set"); 45 | Assert.notNull(this.messages, "A message source must be set"); 46 | this.doAfterPropertiesSet(); 47 | } 48 | 49 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 50 | String username = authentication.getPrincipal() == null?"NONE_PROVIDED":authentication.getName(); 51 | boolean cacheWasUsed = true; 52 | UserDetails user = this.userCache.getUserFromCache(username); 53 | if(user == null) { 54 | cacheWasUsed = false; 55 | 56 | try { 57 | user = this.retrieveUser(username, authentication); 58 | } catch (UsernameNotFoundException var6) { 59 | this.logger.debug("User \'" + username + "\' not found"); 60 | if(this.hideUserNotFoundExceptions) { 61 | throw new BadCredentialsException(this.messages.getMessage("MyAbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); 62 | } 63 | 64 | throw var6; 65 | } 66 | 67 | Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract"); 68 | } 69 | 70 | try { 71 | this.preAuthenticationChecks.check(user); 72 | this.additionalAuthenticationChecks(user, authentication); 73 | } catch (AuthenticationException var7) { 74 | if(!cacheWasUsed) { 75 | throw var7; 76 | } 77 | 78 | cacheWasUsed = false; 79 | user = this.retrieveUser(username, authentication); 80 | this.preAuthenticationChecks.check(user); 81 | this.additionalAuthenticationChecks(user, authentication); 82 | } 83 | 84 | this.postAuthenticationChecks.check(user); 85 | if(!cacheWasUsed) { 86 | this.userCache.putUserInCache(user); 87 | } 88 | 89 | Object principalToReturn = user; 90 | if(this.forcePrincipalAsString) { 91 | principalToReturn = user.getUsername(); 92 | } 93 | 94 | return this.createSuccessAuthentication(principalToReturn, authentication, user); 95 | } 96 | 97 | protected abstract Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user); 98 | 99 | protected void doAfterPropertiesSet() throws Exception { 100 | } 101 | 102 | public UserCache getUserCache() { 103 | return this.userCache; 104 | } 105 | 106 | public boolean isForcePrincipalAsString() { 107 | return this.forcePrincipalAsString; 108 | } 109 | 110 | public boolean isHideUserNotFoundExceptions() { 111 | return this.hideUserNotFoundExceptions; 112 | } 113 | 114 | protected abstract UserDetails retrieveUser(String var1, Authentication var2) throws AuthenticationException; 115 | 116 | public void setForcePrincipalAsString(boolean forcePrincipalAsString) { 117 | this.forcePrincipalAsString = forcePrincipalAsString; 118 | } 119 | 120 | public void setHideUserNotFoundExceptions(boolean hideUserNotFoundExceptions) { 121 | this.hideUserNotFoundExceptions = hideUserNotFoundExceptions; 122 | } 123 | 124 | public void setMessageSource(MessageSource messageSource) { 125 | this.messages = new MessageSourceAccessor(messageSource); 126 | } 127 | 128 | public void setUserCache(UserCache userCache) { 129 | this.userCache = userCache; 130 | } 131 | 132 | 133 | protected UserDetailsChecker getPreAuthenticationChecks() { 134 | return this.preAuthenticationChecks; 135 | } 136 | 137 | public void setPreAuthenticationChecks(UserDetailsChecker preAuthenticationChecks) { 138 | this.preAuthenticationChecks = preAuthenticationChecks; 139 | } 140 | 141 | protected UserDetailsChecker getPostAuthenticationChecks() { 142 | return this.postAuthenticationChecks; 143 | } 144 | 145 | public void setPostAuthenticationChecks(UserDetailsChecker postAuthenticationChecks) { 146 | this.postAuthenticationChecks = postAuthenticationChecks; 147 | } 148 | 149 | public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) { 150 | this.authoritiesMapper = authoritiesMapper; 151 | } 152 | 153 | private class DefaultPostAuthenticationChecks implements UserDetailsChecker { 154 | private DefaultPostAuthenticationChecks() { 155 | } 156 | 157 | public void check(UserDetails user) { 158 | if(!user.isCredentialsNonExpired()) { 159 | MyAbstractUserDetailsAuthenticationProvider.this.logger.debug("User account credentials have expired"); 160 | throw new CredentialsExpiredException(MyAbstractUserDetailsAuthenticationProvider.this.messages.getMessage("MyAbstractUserDetailsAuthenticationProvider.credentialsExpired", "User credentials have expired")); 161 | } 162 | } 163 | } 164 | 165 | private class DefaultPreAuthenticationChecks implements UserDetailsChecker { 166 | private DefaultPreAuthenticationChecks() { 167 | } 168 | 169 | public void check(UserDetails user) { 170 | if(!user.isAccountNonLocked()) { 171 | MyAbstractUserDetailsAuthenticationProvider.this.logger.debug("User account is locked"); 172 | throw new LockedException(MyAbstractUserDetailsAuthenticationProvider.this.messages.getMessage("MyAbstractUserDetailsAuthenticationProvider.locked", "User account is locked")); 173 | } else if(!user.isEnabled()) { 174 | MyAbstractUserDetailsAuthenticationProvider.this.logger.debug("User account is disabled"); 175 | throw new DisabledException(MyAbstractUserDetailsAuthenticationProvider.this.messages.getMessage("MyAbstractUserDetailsAuthenticationProvider.disabled", "User is disabled")); 176 | } else if(!user.isAccountNonExpired()) { 177 | MyAbstractUserDetailsAuthenticationProvider.this.logger.debug("User account is expired"); 178 | throw new AccountExpiredException(MyAbstractUserDetailsAuthenticationProvider.this.messages.getMessage("MyAbstractUserDetailsAuthenticationProvider.expired", "User account has expired")); 179 | } 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/provider/MyPhoneAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.provider; 2 | 3 | 4 | import com.wwz.frame.token.MyPhoneAuthenticationToken; 5 | import org.springframework.security.authentication.BadCredentialsException; 6 | import org.springframework.security.authentication.InternalAuthenticationServiceException; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.AuthenticationException; 9 | import org.springframework.security.core.userdetails.UserDetails; 10 | import org.springframework.security.core.userdetails.UserDetailsService; 11 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 12 | 13 | /** 14 | * @Description 手机验证码登录 15 | * @Author wwz 16 | * @Date 2019/08/04 17 | * @Param 18 | * @Return 19 | */ 20 | public class MyPhoneAuthenticationProvider extends MyAbstractUserDetailsAuthenticationProvider { 21 | 22 | private UserDetailsService userDetailsService; 23 | 24 | @Override 25 | protected void additionalAuthenticationChecks(UserDetails var1, Authentication authentication) throws AuthenticationException { 26 | 27 | if(authentication.getPrincipal() == null){ 28 | throw new BadCredentialsException(this.messages.getMessage("MyPhoneAuthenticationProvider.badPrincipal", "Bad badPrincipal")); 29 | } 30 | if (authentication.getCredentials() == null) { 31 | throw new BadCredentialsException(this.messages.getMessage("MyPhoneAuthenticationProvider.badCredentials", "Bad credentials")); 32 | } else { 33 | String phoneCode = authentication.getCredentials().toString(); 34 | // String phoneNumber = authentication.getPrincipal().toString(); 35 | // 36 | // String old_code = (String) redisTemplate.opsForValue().get(phoneNumber+"_code"); 37 | // 38 | // if(old_code==null){ 39 | // // 验证码未获取或已经失效 40 | // throw new BadCredentialsException(this.messages.getMessage("MyPhoneAuthenticationProvider.badCredentials", "Bad phoneCode")); 41 | // } 42 | // if(!phoneCode.equals(old_code)){ 43 | // // 验证码错误 44 | // throw new BadCredentialsException(this.messages.getMessage("MyPhoneAuthenticationProvider.badCredentials", "Bad phoneCode")); 45 | // } 46 | if (!"1234".equals(phoneCode)) { 47 | throw new BadCredentialsException(this.messages.getMessage("MyPhoneAuthenticationProvider.badCredentials", "Bad phoneCode")); 48 | } 49 | } 50 | } 51 | 52 | @Override 53 | protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) { 54 | MyPhoneAuthenticationToken result = new MyPhoneAuthenticationToken(principal, authentication.getCredentials(), user.getAuthorities()); 55 | result.setDetails(authentication.getDetails()); 56 | return result; 57 | } 58 | 59 | @Override 60 | protected UserDetails retrieveUser(String phone, Authentication authentication) throws AuthenticationException { 61 | UserDetails loadedUser; 62 | try { 63 | loadedUser = this.getUserDetailsService().loadUserByUsername(phone); 64 | } catch (UsernameNotFoundException var6) { 65 | throw var6; 66 | } catch (Exception var7) { 67 | throw new InternalAuthenticationServiceException(var7.getMessage(), var7); 68 | } 69 | 70 | if (loadedUser == null) { 71 | throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation"); 72 | } else { 73 | return loadedUser; 74 | } 75 | } 76 | 77 | @Override 78 | public boolean supports(Class authentication) { 79 | return MyPhoneAuthenticationToken.class.isAssignableFrom(authentication); 80 | } 81 | 82 | 83 | public UserDetailsService getUserDetailsService() { 84 | return userDetailsService; 85 | } 86 | 87 | public void setUserDetailsService(UserDetailsService userDetailsService) { 88 | this.userDetailsService = userDetailsService; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/service/MyClientDetails.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.service; 2 | 3 | import com.wwz.frame.common.CommonUtils; 4 | import com.wwz.frame.entity.AuthClientDetails; 5 | import org.springframework.security.core.GrantedAuthority; 6 | import org.springframework.security.core.authority.AuthorityUtils; 7 | import org.springframework.security.oauth2.provider.ClientDetails; 8 | 9 | import java.util.*; 10 | 11 | /** 12 | * @Description 自定义实现ClientDetails 不能使用lombok 13 | * @Author wwz 14 | * @Date 2019/07/28 15 | * @Param 16 | * @Return 17 | */ 18 | public class MyClientDetails implements ClientDetails { 19 | private AuthClientDetails client; 20 | 21 | public MyClientDetails(AuthClientDetails client) { 22 | this.client = client; 23 | } 24 | 25 | public MyClientDetails() { 26 | 27 | } 28 | 29 | /** 30 | * The client id. 31 | * 32 | * @return The client id. 33 | */ 34 | @Override 35 | public String getClientId() { 36 | return client.getClientId(); 37 | } 38 | 39 | /** 40 | * The resources that this client can access. Can be ignored by callers if empty. 41 | * 42 | * @return The resources of this client. 43 | */ 44 | @Override 45 | public Set getResourceIds() { 46 | return client.getResourceIds() != null ? 47 | CommonUtils.transformStringToSet(client.getResourceIds(), String.class) : Collections.emptySet(); 48 | } 49 | 50 | /** 51 | * Whether a secret is required to authenticate this client. 52 | * 53 | * @return Whether a secret is required to authenticate this client. 54 | */ 55 | @Override 56 | public boolean isSecretRequired() { 57 | return client.getClientSecret() != null; 58 | } 59 | 60 | /** 61 | * The client secret. Ignored if the {@link #isSecretRequired() secret isn't required}. 62 | * 63 | * @return The client secret. 64 | */ 65 | @Override 66 | public String getClientSecret() { 67 | return client.getClientSecret(); 68 | } 69 | 70 | /** 71 | * Whether this client is limited to a specific scope. If false, the scope of the authentication request will be 72 | * ignored. 73 | * 74 | * @return Whether this client is limited to a specific scope. 75 | */ 76 | @Override 77 | public boolean isScoped() { 78 | return this.getScope() != null && !this.getScope().isEmpty(); 79 | } 80 | 81 | /** 82 | * The scope of this client. Empty if the client isn't scoped. 83 | * 84 | * @return The scope of this client. 85 | */ 86 | @Override 87 | public Set getScope() { 88 | return client.getScopes() != null ? 89 | CommonUtils.transformStringToSet(client.getScopes(), String.class) : Collections.emptySet(); 90 | } 91 | 92 | /** 93 | * The grant types for which this client is authorized. 94 | * 95 | * @return The grant types for which this client is authorized. 96 | */ 97 | @Override 98 | public Set getAuthorizedGrantTypes() { 99 | return client.getAuthorizedGrantTypes() != null ? 100 | CommonUtils.transformStringToSet(client.getAuthorizedGrantTypes(), String.class) : Collections.emptySet(); 101 | } 102 | 103 | /** 104 | * The pre-defined redirect URI for this client to use during the "authorization_code" access grant. See OAuth spec, 105 | * section 4.1.1. 106 | * 107 | * @return The pre-defined redirect URI for this client. 108 | */ 109 | @Override 110 | public Set getRegisteredRedirectUri() { 111 | return client.getWebServerRedirectUris() != null ? 112 | CommonUtils.transformStringToSet(client.getWebServerRedirectUris(), String.class) : Collections.emptySet(); 113 | } 114 | 115 | /** 116 | * Returns the authorities that are granted to the OAuth client. Cannot return null. 117 | * Note that these are NOT the authorities that are granted to the user with an authorized access token. 118 | * Instead, these authorities are inherent to the client itself. 119 | * 120 | * @return the authorities (never null) 121 | */ 122 | @Override 123 | public Collection getAuthorities() { 124 | return (client.getAuthorities() != null && client.getAuthorities().trim().length() > 0) ? 125 | AuthorityUtils.commaSeparatedStringToAuthorityList(client.getAuthorities()) : Collections.emptyList(); 126 | } 127 | 128 | /** 129 | * The access token validity period for this client. Null if not set explicitly (implementations might use that fact 130 | * to provide a default value for instance). 131 | * 132 | * @return the access token validity period 133 | */ 134 | @Override 135 | public Integer getAccessTokenValiditySeconds() { 136 | return client.getAccessTokenValidity(); 137 | } 138 | 139 | /** 140 | * The refresh token validity period for this client. Null for default value set by token service, and 141 | * zero or negative for non-expiring tokens. 142 | * 143 | * @return the refresh token validity period 144 | */ 145 | @Override 146 | public Integer getRefreshTokenValiditySeconds() { 147 | return client.getRefreshTokenValidity(); 148 | } 149 | 150 | /** 151 | * Test whether client needs user approval for a particular scope. 152 | * 153 | * @param scope the scope to consider 154 | * @return true if this client does not need user approval 155 | */ 156 | @Override 157 | public boolean isAutoApprove(String scope) { 158 | if (this.getAutoApproveScopes() == null) { 159 | return false; 160 | } else { 161 | Iterator var2 = this.getAutoApproveScopes().iterator(); 162 | String auto; 163 | do { 164 | if (!var2.hasNext()) { 165 | return false; 166 | } 167 | auto = (String) var2.next(); 168 | } while (!auto.equals("true") && !scope.matches(auto)); 169 | return true; 170 | } 171 | } 172 | 173 | /** 174 | * Additional information for this client, not needed by the vanilla OAuth protocol but might be useful, for example, 175 | * for storing descriptive information. 176 | * 177 | * @return a map of additional information 178 | */ 179 | @Override 180 | public Map getAdditionalInformation() { 181 | return null; 182 | } 183 | 184 | public Set getAutoApproveScopes() { 185 | return client.getAutoApprove() != null ? 186 | CommonUtils.transformStringToSet(client.getAutoApprove(), String.class) : Collections.emptySet(); 187 | } 188 | 189 | @Override 190 | public int hashCode() { 191 | final int prime = 31; 192 | int result = 1; 193 | result = prime 194 | * result 195 | + ((client.getAccessTokenValidity() == null) ? 0 196 | : client.getAccessTokenValidity()); 197 | result = prime 198 | * result 199 | + ((client.getRefreshTokenValidity() == null) ? 0 200 | : client.getRefreshTokenValidity()); 201 | result = prime * result 202 | + ((client.getAuthorities() == null) ? 0 : client.getAuthorities().hashCode()); 203 | result = prime 204 | * result 205 | + ((client.getAuthorizedGrantTypes() == null) ? 0 : client.getAuthorizedGrantTypes() 206 | .hashCode()); 207 | result = prime * result 208 | + ((client.getClientId() == null) ? 0 : client.getClientId().hashCode()); 209 | result = prime * result 210 | + ((client.getClientSecret() == null) ? 0 : client.getClientSecret().hashCode()); 211 | result = prime 212 | * result 213 | + ((client.getWebServerRedirectUris() == null) ? 0 214 | : client.getWebServerRedirectUris().hashCode()); 215 | result = prime * result 216 | + ((client.getResourceIds() == null) ? 0 : client.getResourceIds().hashCode()); 217 | result = prime * result + ((client.getScopes() == null) ? 0 : client.getScopes().hashCode()); 218 | result = prime * result + ((client.getAdditionalInformation() == null) ? 0 : client.getAdditionalInformation().hashCode()); 219 | return result; 220 | } 221 | 222 | @Override 223 | public boolean equals(Object obj) { 224 | if (this == obj) 225 | return true; 226 | if (obj == null) 227 | return false; 228 | if (getClass() != obj.getClass()) 229 | return false; 230 | AuthClientDetails other = (AuthClientDetails) obj; 231 | if (client.getAccessTokenValidity() == null) { 232 | if (other.getAccessTokenValidity() != null) 233 | return false; 234 | } else if (!client.getAccessTokenValidity().equals(other.getAccessTokenValidity())) 235 | return false; 236 | if (client.getRefreshTokenValidity() == null) { 237 | if (other.getRefreshTokenValidity() != null) 238 | return false; 239 | } else if (!client.getRefreshTokenValidity().equals(other.getRefreshTokenValidity())) 240 | return false; 241 | if (client.getAuthorities() == null) { 242 | if (other.getAuthorities() != null) 243 | return false; 244 | } else if (!client.getAuthorities().equals(other.getAuthorities())) 245 | return false; 246 | if (client.getAuthorizedGrantTypes() == null) { 247 | if (other.getAuthorizedGrantTypes() != null) 248 | return false; 249 | } else if (!client.getAuthorizedGrantTypes().equals(other.getAuthorizedGrantTypes())) 250 | return false; 251 | if (client.getClientId() == null) { 252 | if (other.getClientId() != null) 253 | return false; 254 | } else if (!client.getClientId().equals(other.getClientId())) 255 | return false; 256 | if (client.getClientSecret() == null) { 257 | if (other.getClientSecret() != null) 258 | return false; 259 | } else if (!client.getClientSecret().equals(other.getClientSecret())) 260 | return false; 261 | if (client.getWebServerRedirectUris() == null) { 262 | if (other.getWebServerRedirectUris() != null) 263 | return false; 264 | } else if (!client.getWebServerRedirectUris().equals(other.getWebServerRedirectUris())) 265 | return false; 266 | if (client.getResourceIds() == null) { 267 | if (other.getResourceIds() != null) 268 | return false; 269 | } else if (!client.getResourceIds().equals(other.getResourceIds())) 270 | return false; 271 | if (client.getScopes() == null) { 272 | if (other.getScopes() != null) 273 | return false; 274 | } else if (!client.getScopes().equals(other.getScopes())) 275 | return false; 276 | if (client.getAdditionalInformation() == null) { 277 | if (other.getAdditionalInformation() != null) 278 | return false; 279 | } else if (!client.getAdditionalInformation().equals(other.getAdditionalInformation())) 280 | return false; 281 | return true; 282 | } 283 | 284 | @Override 285 | public String toString() { 286 | return "AuthClientDetails [clientId=" + client.getClientId() + ", clientSecret=" 287 | + client.getClientSecret() + ", scope=" + client.getScopes() + ", resourceIds=" 288 | + client.getResourceIds() + ", authorizedGrantTypes=" 289 | + client.getAuthorizedGrantTypes() + ", registeredRedirectUris=" 290 | + client.getWebServerRedirectUris() + ", authorities=" + client.getAuthorities() 291 | + ", accessTokenValiditySeconds=" + client.getAccessTokenValidity() 292 | + ", refreshTokenValiditySeconds=" 293 | + client.getRefreshTokenValidity() + ", additionalInformation=" 294 | + client.getAdditionalInformation() + "]"; 295 | } 296 | 297 | 298 | } 299 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/service/MyClientDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.service; 2 | 3 | import com.wwz.frame.entity.AuthClientDetails; 4 | import com.wwz.frame.mapper.AuthClientDetailsMapper; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.oauth2.provider.ClientDetails; 7 | import org.springframework.security.oauth2.provider.ClientDetailsService; 8 | import org.springframework.security.oauth2.provider.ClientRegistrationException; 9 | import org.springframework.stereotype.Service; 10 | /** 11 | * @Description 自定义客户端数据 12 | * @Author wwz 13 | * @Date 2019/07/28 14 | * @Param 15 | * @Return 16 | */ 17 | @Service 18 | public class MyClientDetailsService implements ClientDetailsService { 19 | @Autowired 20 | private AuthClientDetailsMapper authClientDetailsMapper; 21 | 22 | /** 23 | * Load a client by the client id. This method must not return null. 24 | * 25 | * @param clientId The client id. 26 | * @return The client details (never null). 27 | * @throws ClientRegistrationException If the client account is locked, expired, disabled, or invalid for any other reason. 28 | */ 29 | @Override 30 | public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException { 31 | AuthClientDetails clientDetails = authClientDetailsMapper.selectClientDetailsByClientId(clientId); 32 | if (clientDetails == null) { 33 | throw new ClientRegistrationException("该客户端不存在"); 34 | } 35 | MyClientDetails details = new MyClientDetails(clientDetails); 36 | return details; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/service/MyPhoneUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.service; 2 | 3 | import com.wwz.frame.entity.AuthUser; 4 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 5 | import org.springframework.stereotype.Service; 6 | /** 7 | * @Description 为手机验证码登录提供数据 8 | * @Author wwz 9 | * @Date 2019/08/05 10 | * @Param 11 | * @Return 12 | */ 13 | @Service 14 | public class MyPhoneUserDetailsService extends MyUserDetailsService { 15 | @Override 16 | protected AuthUser getUser(String var1) { 17 | // 手机验证码登录使用,根据手机号码查询用户信息 18 | AuthUser authUser = authUserMapper.selectByPhone(var1); 19 | if (authUser == null) { 20 | throw new UsernameNotFoundException("找不到该用户,手机号码有误:" + var1); 21 | } 22 | return authUser; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/service/MyUserDetails.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.service; 2 | 3 | import com.wwz.frame.entity.AuthUser; 4 | import lombok.Data; 5 | import org.springframework.security.core.GrantedAuthority; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | 8 | import java.util.Collection; 9 | 10 | /** 11 | * @Description 自定义实现UserDetails 12 | * @Author wwz 13 | * @Date 2019/07/28 14 | * @Param 15 | * @Return 16 | */ 17 | @Data 18 | public class MyUserDetails implements UserDetails { 19 | private AuthUser user; 20 | 21 | private Collection authorities; 22 | 23 | public MyUserDetails(AuthUser user, Collection authorities) { 24 | this.user = user; 25 | this.authorities = authorities; 26 | } 27 | 28 | public MyUserDetails() { 29 | } 30 | 31 | @Override 32 | public Collection getAuthorities() { 33 | return authorities; 34 | } 35 | 36 | @Override 37 | public String getPassword() { 38 | return user.getPassword(); 39 | } 40 | 41 | @Override 42 | public String getUsername() { 43 | return user.getUsername(); 44 | } 45 | 46 | @Override 47 | public boolean isAccountNonExpired() { 48 | return user.getAccountNonExpired(); 49 | } 50 | 51 | @Override 52 | public boolean isAccountNonLocked() { 53 | return user.getAccountNonLocked(); 54 | } 55 | 56 | @Override 57 | public boolean isCredentialsNonExpired() { 58 | return user.getCredentialsNonExpired(); 59 | } 60 | 61 | @Override 62 | public boolean isEnabled() { 63 | return user.getValid(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/service/MyUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.service; 2 | 3 | import com.wwz.frame.entity.AuthPermission; 4 | import com.wwz.frame.entity.AuthRole; 5 | import com.wwz.frame.entity.AuthUser; 6 | import com.wwz.frame.mapper.AuthUserMapper; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.security.core.GrantedAuthority; 9 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 10 | import org.springframework.security.core.userdetails.UserDetails; 11 | import org.springframework.security.core.userdetails.UserDetailsService; 12 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.util.HashSet; 16 | import java.util.Set; 17 | 18 | /** 19 | * @Description 自定义用户验证数据 20 | * @Author wwz 21 | * @Date 2019/07/28 22 | * @Param 23 | * @Return 24 | */ 25 | 26 | @Service 27 | public abstract class MyUserDetailsService implements UserDetailsService { 28 | 29 | @Autowired 30 | protected AuthUserMapper authUserMapper; 31 | 32 | @Override 33 | public UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException { 34 | // 自定义用户权限数据 35 | AuthUser authUser1 = getUser(var1); 36 | 37 | AuthUser authUser = authUserMapper.selectById(authUser1.getId()); 38 | if (authUser == null) { 39 | throw new UsernameNotFoundException("用户名不存在"); 40 | } 41 | if (!authUser.getValid()) { 42 | throw new UsernameNotFoundException("用户不可用"); 43 | } 44 | Set grantedAuthorities = new HashSet<>(); 45 | if (authUser.getAuthRoles() != null) { 46 | for (AuthRole role : authUser.getAuthRoles()) { 47 | // 当前角色可用 48 | if (role.getValid()) { 49 | //角色必须是ROLE_开头 50 | GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleName()); 51 | grantedAuthorities.add(grantedAuthority); 52 | if (role.getAuthPermissions() != null) { 53 | for (AuthPermission permission : role.getAuthPermissions()) { 54 | // 当前权限可用 55 | if (permission.getValid()) { 56 | // 拥有权限设置为 auth/member/GET 可以访问auth服务下面 member的查询方法 57 | GrantedAuthority authority = new SimpleGrantedAuthority(permission.getServicePrefix() + "/" + permission.getUri() + "/" + permission.getMethod()); 58 | grantedAuthorities.add(authority); 59 | } 60 | } 61 | } 62 | } 63 | //获取权限 64 | } 65 | } 66 | MyUserDetails userDetails = new MyUserDetails(authUser, grantedAuthorities); 67 | return userDetails; 68 | } 69 | 70 | 71 | protected abstract AuthUser getUser(String var1); 72 | } 73 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/service/MyUsernameUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.service; 2 | 3 | import com.wwz.frame.entity.AuthUser; 4 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 5 | import org.springframework.stereotype.Service; 6 | /** 7 | * @Description 为默认的token登录方式提供数据 8 | * @Author wwz 9 | * @Date 2019/08/05 10 | * @Param 11 | * @Return 12 | */ 13 | @Service 14 | public class MyUsernameUserDetailsService extends MyUserDetailsService { 15 | @Override 16 | protected AuthUser getUser(String var1) { 17 | // 账号密码登录根据用户名查询用户 18 | AuthUser authUser = authUserMapper.selectByUsername(var1); 19 | if (authUser == null) { 20 | throw new UsernameNotFoundException("找不到该用户,用户名:" + var1); 21 | } 22 | return authUser; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/token/MyAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.token; 2 | 3 | import org.springframework.security.authentication.AbstractAuthenticationToken; 4 | import org.springframework.security.core.GrantedAuthority; 5 | 6 | import java.util.Collection; 7 | /** 8 | * @Description 自定义AbstractAuthenticationToken 9 | * @Author wwz 10 | * @Date 2019/08/04 11 | * @Param 12 | * @Return 13 | */ 14 | public class MyAuthenticationToken extends AbstractAuthenticationToken { 15 | 16 | private static final long serialVersionUID = 110L; 17 | protected final Object principal; 18 | protected Object credentials; 19 | 20 | /** 21 | * This constructor can be safely used by any code that wishes to create a 22 | * UsernamePasswordAuthenticationToken, as the {@link 23 | * #isAuthenticated()} will return false. 24 | * 25 | */ 26 | public MyAuthenticationToken(Object principal, Object credentials) { 27 | super(null); 28 | this.principal = principal; 29 | this.credentials = credentials; 30 | this.setAuthenticated(false); 31 | } 32 | 33 | /** 34 | * This constructor should only be used by AuthenticationManager or AuthenticationProvider 35 | * implementations that are satisfied with producing a trusted (i.e. {@link #isAuthenticated()} = true) 36 | * token token. 37 | * 38 | * @param principal 39 | * @param credentials 40 | * @param authorities 41 | */ 42 | public MyAuthenticationToken(Object principal, Object credentials, Collection authorities) { 43 | super(authorities); 44 | this.principal = principal; 45 | this.credentials = credentials; 46 | super.setAuthenticated(true); 47 | } 48 | 49 | 50 | @Override 51 | public Object getCredentials() { 52 | return this.credentials; 53 | } 54 | 55 | @Override 56 | public Object getPrincipal() { 57 | return this.principal; 58 | } 59 | 60 | 61 | public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { 62 | if(isAuthenticated) { 63 | throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); 64 | } else { 65 | super.setAuthenticated(false); 66 | } 67 | } 68 | 69 | public void eraseCredentials() { 70 | super.eraseCredentials(); 71 | this.credentials = null; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/java/com/wwz/frame/token/MyPhoneAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.token; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | 5 | import java.util.Collection; 6 | 7 | /** 8 | * @Description 手机验证token 9 | * @Author wwz 10 | * @Date 2019/08/04 11 | * @Param 12 | * @Return 13 | */ 14 | public class MyPhoneAuthenticationToken extends MyAuthenticationToken { 15 | 16 | public MyPhoneAuthenticationToken(Object principal, Object credentials) { 17 | super(principal, credentials); 18 | } 19 | 20 | public MyPhoneAuthenticationToken(Object principal, Object credentials, Collection authorities) { 21 | super(principal, credentials, authorities); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | #Tomcat 设置最大线程,最小备用线程,端口,请求地址 localhost:8002 2 | server: 3 | tomcat: 4 | max-threads: 100 5 | min-spare-threads: 10 6 | port: 8003 7 | #遇到相同名字是否允许覆盖注册 8 | spring: 9 | main: 10 | allow-bean-definition-overriding: true 11 | application: 12 | name: SpringCloud-consul-authorization-server 13 | #数据库配置 14 | datasource: 15 | driver-class-name: com.mysql.jdbc.Driver 16 | url: jdbc:mysql://127.0.0.1:3306/frame-permission?useUnicode=true&characterEncoding=UTF-8&useSSL=false 17 | username: root 18 | password: wwzroot 19 | type: com.alibaba.druid.pool.DruidDataSource 20 | #连接池的补充设置 21 | druid: 22 | minIdle: 5 23 | minEvictableIdleTimeMillis: 300000 24 | timeBetweenEvictionRunsMillis: 60000 25 | initialSize: 5 26 | maxWait: 60000 27 | maxActive: 20 28 | connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 29 | maxPoolPreparedStatementPerConnectionSize: 20 30 | useGlobalDataSourceStat: true 31 | testWhileIdle: true 32 | testOnBorrow: false 33 | testOnReturn: false 34 | filters: stat,wall,log4j 35 | poolPreparedStatements: true 36 | 37 | #redis服务器地址配置 38 | redis: 39 | host: 192.168.1.130 40 | port: 6379 41 | #mybatis配置 42 | mybatis: 43 | configuration: 44 | cache-enabled: true 45 | lazy-loading-enabled: true 46 | aggressive-lazy-loading: true 47 | jdbc-type-for-null: NULL 48 | map-underscore-to-camel-case: true 49 | call-setters-on-nulls: true 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weizongwu/SpringCloud-OAuth2-SpringSecurity-Frame/167412684bcb1d0488dc2e0d860142733964a178/fp-authorization-server/src/main/resources/application-test.yml -------------------------------------------------------------------------------- /fp-authorization-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #指定为 调用application-dev.xml 2 | spring: 3 | profiles: 4 | active: dev 5 | 6 | 7 | -------------------------------------------------------------------------------- /fp-authorization-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | #port 端口 host 地址 serviceName 注册名称 register:是否注册到consul 默认为false 2 | spring: 3 | cloud: 4 | consul: 5 | port: 8500 6 | host: 192.168.1.130 7 | discovery: 8 | serviceName: auth 9 | locator: 10 | lower-case-service-id: true 11 | enabled: true 12 | register: true 13 | prefer-ip-address: true #这个必须配 14 | tags: version=1.0 15 | instance-id: ${spring.application.name}:${spring.cloud.client.ip-address} 16 | health-check-critical-timeout: 60s #多少秒健康检查不过,从consul中删除服务 17 | healthCheckInterval: 15s 18 | health-check-url: http://${spring.cloud.client.ip-address}:${server.port}/actuator/health -------------------------------------------------------------------------------- /fp-commons/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | SpringCloud-OAuth2-SpringSecurity-Frame 7 | com.wwz.frame 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | com.wwz.frame 12 | fp-commons 13 | 1.0-SNAPSHOT 14 | fp-commons 15 | jar 16 | 公用类项目 17 | 18 | 19 | UTF-8 20 | 1.8 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-web 26 | 27 | 28 | org.projectlombok 29 | lombok 30 | 31 | 32 | io.springfox 33 | springfox-swagger2 34 | 35 | 36 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/CommonsApplication.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | 5 | //@SpringBootApplication SpringBoot Test的时候会被这里影响,测试的是注释掉。 6 | public class CommonsApplication { 7 | public static void main(String[] args) { 8 | SpringApplication.run(CommonsApplication.class, args); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/annotation/OperationLog.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @Description 操作日志 7 | * @Author wwz 8 | * @Date 2019/07/26 9 | * @Param 10 | * @Return 11 | */ 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Documented 15 | public @interface OperationLog { 16 | 17 | String description() default ""; 18 | } 19 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/common/CodeEnum.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.common; 2 | /** 3 | * @Description 枚举返回 4 | * @Author wwz 5 | * @Date 2019/07/26 6 | * @Param 7 | * @Return 8 | */ 9 | public enum CodeEnum { 10 | ADD_SUCCESS(100,"新增成功"), 11 | ADD_FAIL(101,"新增失败!"), 12 | MODIFY_SUCCESS(110,"修改成功!"), 13 | MODIFY_FAIL(111,"修改失败!"), 14 | REMOVE_SUCCESS(120,"删除成功!"), 15 | REMOVE_FAIL(121,"删除失败!"), 16 | LOGIN_SUCCESS(130,"登录成功"); 17 | 18 | private Integer code; 19 | private String msg; 20 | 21 | CodeEnum(Integer code,String msg) { 22 | this.code = code; 23 | this.msg = msg; 24 | } 25 | 26 | public Integer getCode() { 27 | return code; 28 | } 29 | 30 | public String getMsg() { 31 | return msg; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/common/CommonUtils.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.common; 2 | 3 | 4 | import java.beans.BeanInfo; 5 | import java.beans.Introspector; 6 | import java.beans.PropertyDescriptor; 7 | import java.lang.reflect.Method; 8 | import java.text.ParseException; 9 | import java.text.SimpleDateFormat; 10 | import java.util.*; 11 | 12 | /** 13 | * @Description 工具转换类 14 | * @Author wwz 15 | * @Date 2019/07/10 16 | * @Param 17 | * @Return 18 | */ 19 | 20 | 21 | public final class CommonUtils { 22 | 23 | /*public static String stringFormat(String target, Object... source) { 24 | StringExpression expression = StringFormatter.format(target, source); 25 | return expression.getValue(); 26 | }*/ 27 | 28 | public static Date dateFormat(String dateStr) { 29 | 30 | SimpleDateFormat mt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 31 | 32 | try { 33 | return mt.parse(dateStr); 34 | } catch (ParseException e) { 35 | e.printStackTrace(); 36 | } 37 | return null; 38 | } 39 | 40 | 41 | /** 42 | * 参数转换,将"1,2,3"转换为[1,2,3]集合 43 | * 44 | * @param str 45 | * @param type 46 | * @return 47 | */ 48 | public static List transformStringToList(String str, Class type) { 49 | 50 | List parameters = new ArrayList<>(); 51 | 52 | String[] tmps = str.trim().split(","); 53 | 54 | String typeName = type.getSimpleName(); 55 | 56 | switch (typeName) { 57 | case "Byte": 58 | for (String item : tmps) { 59 | try { 60 | Byte var1 = Byte.parseByte(item); 61 | parameters.add(var1); 62 | } catch (Exception e) { 63 | throw e; 64 | } 65 | } 66 | break; 67 | case "Long": 68 | for (String item : tmps) { 69 | try { 70 | Long var1 = Long.parseLong(item); 71 | parameters.add(var1); 72 | } catch (Exception e) { 73 | throw e; 74 | } 75 | } 76 | default: 77 | for (String item : tmps) { 78 | parameters.add(item); 79 | } 80 | } 81 | return parameters; 82 | } 83 | 84 | 85 | public static Set transformStringToSet(String str, Class type) { 86 | 87 | Set parameters = new HashSet<>(); 88 | 89 | String[] tmps = str.trim().split(","); 90 | 91 | String typeName = type.getSimpleName(); 92 | switch (typeName) { 93 | case "Byte": 94 | for (String item : tmps) { 95 | try { 96 | Byte var1 = Byte.parseByte(item); 97 | parameters.add(var1); 98 | } catch (Exception e) { 99 | throw e; 100 | } 101 | } 102 | break; 103 | case "Long": 104 | for (String item : tmps) { 105 | try { 106 | Long var1 = Long.parseLong(item); 107 | parameters.add(var1); 108 | } catch (Exception e) { 109 | throw e; 110 | } 111 | } 112 | default: 113 | for (String item : tmps) { 114 | parameters.add(item); 115 | } 116 | } 117 | 118 | return parameters; 119 | } 120 | 121 | /** 122 | * Map转换为对象 123 | * 124 | * @param map 125 | * @param target 126 | * @return 127 | * @throws Exception 128 | */ 129 | public static Object transformMapToObject(Map map, Class target) throws Exception { 130 | 131 | BeanInfo beanInfo = Introspector.getBeanInfo(target); 132 | 133 | // 获取所有属性 134 | PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); 135 | 136 | Object obj = target.newInstance(); 137 | 138 | for (PropertyDescriptor descriptor : descriptors) { 139 | 140 | // map中是否包含该属性 141 | if (map.containsKey(descriptor.getName())) { 142 | 143 | String propertySimpleName = descriptor.getPropertyType().getSimpleName(); 144 | 145 | String key = descriptor.getName(); 146 | 147 | if (propertySimpleName.equals("Byte") || propertySimpleName.equals("byte")) { 148 | Byte byteValue = Byte.parseByte(String.valueOf(map.get(key))); 149 | descriptor.getWriteMethod().invoke(obj, byteValue); 150 | continue; 151 | } 152 | 153 | if (propertySimpleName.equals("Long") || propertySimpleName.equals("long")) { 154 | Long longValue = Long.parseLong(String.valueOf(map.get(key))); 155 | descriptor.getWriteMethod().invoke(obj, longValue); 156 | continue; 157 | } 158 | 159 | if (propertySimpleName.equals("Short") || propertySimpleName.equals("short")) { 160 | Short shortValue = Short.parseShort(String.valueOf(map.get(key))); 161 | descriptor.getWriteMethod().invoke(obj, shortValue); 162 | continue; 163 | } 164 | 165 | if (propertySimpleName.equals("Double") || propertySimpleName.equals("double")) { 166 | Double doubleValue = Double.parseDouble(String.valueOf(map.get(key))); 167 | descriptor.getWriteMethod().invoke(obj, doubleValue); 168 | continue; 169 | } 170 | 171 | if (propertySimpleName.equals("Float") || propertySimpleName.equals("float")) { 172 | Float floatValue = Float.parseFloat(String.valueOf(map.get(key))); 173 | descriptor.getWriteMethod().invoke(obj, floatValue); 174 | continue; 175 | } 176 | 177 | // 如果不符合上述条件 178 | Object value = map.get(key); 179 | descriptor.getWriteMethod().invoke(obj, value); 180 | 181 | } 182 | 183 | } 184 | 185 | return obj; 186 | } 187 | 188 | /** 189 | * 将source中的属性值赋给target中属性; 190 | * 如果source中的属性值不为空就进行赋值操作 191 | * 192 | * @param source 193 | * @param target 目标赋值类 194 | * @return 195 | * @throws Exception 196 | */ 197 | public static Object copy(Object source, Object target) throws Exception { 198 | 199 | // 获取对象的描述信息 200 | BeanInfo sf = Introspector.getBeanInfo(source.getClass()); 201 | BeanInfo tf = Introspector.getBeanInfo(target.getClass()); 202 | 203 | // 获取属性描述信息,其中包括 属性名称,类型,属性的读写方法 204 | PropertyDescriptor[] desSf = sf.getPropertyDescriptors(); 205 | PropertyDescriptor[] desTf = tf.getPropertyDescriptors(); 206 | 207 | for (PropertyDescriptor var1 : desSf) { 208 | // 如果该属性名是class 并且类型为Class 则跳过 209 | if (var1.getName().equals("class") && var1.getPropertyType().getSimpleName().equals("Class")) continue; 210 | 211 | for (PropertyDescriptor var2 : desTf) { 212 | 213 | // 如果该属性名是class 并且类型为Class 则跳过 214 | if (var1.getName().equals("class") && var2.getPropertyType().getSimpleName().equals("Class")) continue; 215 | 216 | if (var1.getName().equals(var2.getName())) { 217 | 218 | Method methodSf = var1.getReadMethod(); 219 | Object obj = methodSf.invoke(source); 220 | // 如果该属性的读方法返回的值不为空则进行赋值 221 | if (obj != null) { 222 | Method methodTf = var2.getWriteMethod(); 223 | // 反射 调用target 对应属性的写方法 224 | methodTf.invoke(target, obj); 225 | } 226 | 227 | } 228 | } 229 | } 230 | return target; 231 | } 232 | 233 | /** 234 | * 随机生成UUID 235 | */ 236 | public static String uuid32Generator() { 237 | 238 | UUID uuid = UUID.randomUUID(); 239 | String uuidStr = uuid.toString().replace("-", ""); 240 | return uuidStr; 241 | } 242 | 243 | 244 | } 245 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/common/HttpUtilsResultVO.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.common; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | 5 | import javax.servlet.http.HttpServletResponse; 6 | import java.io.IOException; 7 | 8 | /** 9 | * @Description 异常直接返回工具类 10 | * @Author wwz 11 | * @Date 2019/07/10 12 | * @Param 13 | * @Return 14 | */ 15 | public class HttpUtilsResultVO { 16 | 17 | public static void writerError(ResponseVo r, HttpServletResponse response) throws IOException { 18 | response.setContentType("application/json,charset=utf-8"); 19 | response.setStatus(r.getCode()); 20 | ObjectMapper objectMapper = new ObjectMapper(); 21 | objectMapper.writeValue(response.getOutputStream(), r); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/common/LinkStringUtil.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.common; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.net.URLEncoder; 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | public class LinkStringUtil { 11 | /** 12 | * map转 链接形式 13 | * 14 | * @param params 15 | * @return 16 | * @throws UnsupportedEncodingException 17 | */ 18 | public static String createLinkStringByGet(Map params) throws UnsupportedEncodingException { 19 | List keys = new ArrayList(params.keySet()); 20 | Collections.sort(keys); 21 | String str = ""; 22 | for (int i = 0; i < keys.size(); i++) { 23 | String key = keys.get(i); 24 | String value = (String) params.get(key); 25 | value = URLEncoder.encode(value, "UTF-8"); 26 | if (i == keys.size() - 1) { 27 | str = str + key + "=" + value; 28 | } else { 29 | str = str + key + "=" + value + "&"; 30 | } 31 | 32 | } 33 | return str; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/common/ResponseVo.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.common; 2 | /** 3 | * @Description 统一返回格式 4 | * @Author wwz 5 | * @Date 2019/07/26 6 | * @Param 7 | * @Return 8 | */ 9 | public class ResponseVo { 10 | private Integer code; 11 | private String message; 12 | private T data; 13 | 14 | public ResponseVo() { 15 | this(200, "", null); 16 | } 17 | 18 | public ResponseVo(T data) { 19 | this(); 20 | if (data instanceof Throwable) { 21 | Throwable exception = (Throwable) data; 22 | this.code = -1; 23 | this.message = exception.getMessage(); 24 | } else { 25 | this.data = data; 26 | } 27 | 28 | } 29 | 30 | public ResponseVo(Integer code, String message) { 31 | this(code, message, null); 32 | } 33 | 34 | public ResponseVo(Integer code, String message, T data) { 35 | this.code = code; 36 | this.message = message; 37 | this.data = data; 38 | } 39 | 40 | public Integer getCode() { 41 | return this.code; 42 | } 43 | 44 | public String getMessage() { 45 | return this.message; 46 | } 47 | 48 | public T getData() { 49 | return this.data; 50 | } 51 | 52 | public void setCode(Integer code) { 53 | this.code = code; 54 | } 55 | 56 | public void setMessage(String message) { 57 | this.message = message; 58 | } 59 | 60 | public void setData(T data) { 61 | this.data = data; 62 | } 63 | 64 | public boolean equals(Object o) { 65 | if (o == this) { 66 | return true; 67 | } else if (!(o instanceof ResponseVo)) { 68 | return false; 69 | } else { 70 | ResponseVo other = (ResponseVo) o; 71 | if (!other.canEqual(this)) { 72 | return false; 73 | } else { 74 | label47: 75 | { 76 | Object this$code = this.getCode(); 77 | Object other$code = other.getCode(); 78 | if (this$code == null) { 79 | if (other$code == null) { 80 | break label47; 81 | } 82 | } else if (this$code.equals(other$code)) { 83 | break label47; 84 | } 85 | 86 | return false; 87 | } 88 | 89 | Object this$message = this.getMessage(); 90 | Object other$message = other.getMessage(); 91 | if (this$message == null) { 92 | if (other$message != null) { 93 | return false; 94 | } 95 | } else if (!this$message.equals(other$message)) { 96 | return false; 97 | } 98 | 99 | Object this$data = this.getData(); 100 | Object other$data = other.getData(); 101 | if (this$data == null) { 102 | if (other$data != null) { 103 | return false; 104 | } 105 | } else if (!this$data.equals(other$data)) { 106 | return false; 107 | } 108 | 109 | return true; 110 | } 111 | } 112 | } 113 | 114 | protected boolean canEqual(Object other) { 115 | return other instanceof ResponseVo; 116 | } 117 | 118 | public int hashCode() { 119 | int result = 1; 120 | Object $code = this.getCode(); 121 | result = result * 59 + ($code == null ? 43 : $code.hashCode()); 122 | Object $message = this.getMessage(); 123 | result = result * 59 + ($message == null ? 43 : $message.hashCode()); 124 | Object $data = this.getData(); 125 | result = result * 59 + ($data == null ? 43 : $data.hashCode()); 126 | return result; 127 | } 128 | 129 | public String toString() { 130 | return "ResponseVo(code=" + this.getCode() + ", message=" + this.getMessage() + ", data=" + this.getData() + ")"; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/entity/AuthClientDetails.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.entity; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @Description clientDetail 字段 与默认方法一致 对应数据库oauth_client_details 采用自带的 11 | * @Author wwz 12 | * @Date 2019/07/26 13 | * @Param 14 | * @Return 15 | */ 16 | @Data 17 | @ApiModel(value="AuthClientDetails",description = "客户端实体") 18 | public class AuthClientDetails implements Serializable { 19 | @ApiModelProperty(value = "自增id", name = "id",required = true) 20 | private Integer id; 21 | @ApiModelProperty(value = "客户端id", name = "clientId", required = true) 22 | private String clientId; // 23 | @ApiModelProperty(value = "客户端密码", name = "clientSecret", required = true) 24 | private String clientSecret; // 25 | @ApiModelProperty(value = "资源范围 传值格式示例 auth,audit", name = "resourceIds") 26 | private String resourceIds; // 27 | @ApiModelProperty(value = "资源范围 传值格式示例 auth,audit", name = "scopes") 28 | private String scopes; // 29 | @ApiModelProperty(value = "授权类型 (四种多选或单选) 传值示例 password,authorization_code,client_credentials,refresh_token", name = "authorizedGrantTypes", required = true) 30 | private String authorizedGrantTypes; // 31 | @ApiModelProperty(value = "code返回地址 示例(url为返回地址) url1,url2", name = "webServerRedirectUris") 32 | private String webServerRedirectUris; // 33 | @ApiModelProperty(value = "权限范围 示例 auth,audit", name = "authorities") 34 | private String authorities; // 35 | @ApiModelProperty(value = "token有效时间 秒", name = "accessTokenValidity",required = true) 36 | private Integer accessTokenValidity; // 37 | @ApiModelProperty(value = "刷新token有效时间 秒", name = "refreshTokenValidity",required = true) 38 | private Integer refreshTokenValidity; // 39 | @ApiModelProperty(hidden = true) 40 | private String additionalInformation; // 41 | @ApiModelProperty(hidden = true) 42 | private String autoApprove; // 是否自动授权 默认false 43 | @ApiModelProperty(hidden = true) 44 | private Boolean valid; 45 | } 46 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/entity/AuthPermission.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.entity; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.util.Date; 9 | 10 | /** 11 | * @Description 权限实体 12 | * @Author wwz 13 | * @Date 2019/07/26 14 | * @Param 15 | * @Return 16 | */ 17 | @Data 18 | @ApiModel(value = "AuthPermission", description = "权限实体") 19 | public class AuthPermission implements Serializable { 20 | private static final long serialVersionUID = 1L; 21 | @ApiModelProperty(value = "自增id", name = "id", required = true) 22 | private Integer id; 23 | @ApiModelProperty(value = "权限名称", name = "permissionName", required = true) 24 | private String permissionName; 25 | @ApiModelProperty(value = "服务名", name = "servicePrefix", required = true) 26 | private String servicePrefix; 27 | @ApiModelProperty(value = "请求方式 restful 模式 GET获取 POST 新增 PUT更新 DELETE 删除", name = "method", required = true) 28 | private String method; 29 | @ApiModelProperty(value = "资源地址", name = "uri", required = true) 30 | private String uri; 31 | @ApiModelProperty(value = "是否可用", name = "valid", required = true) 32 | private Boolean valid; 33 | private Date createTime; // 创建时间 34 | private Date updateTime; // 更新时间 35 | @ApiModelProperty(value = "操作用户id", name = "operateId", required = true) 36 | private Integer operateId; // 操作用户id 37 | } 38 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/entity/AuthResource.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.entity; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.util.Date; 9 | 10 | /** 11 | * @Description 资源权限配置实体 12 | * @Author wwz 13 | * @Date 2019/07/26 14 | * @Param 15 | * @Return 16 | */ 17 | @Data 18 | @ApiModel(value = "AuthResource", description = "资源权限配置实体") 19 | public class AuthResource implements Serializable { 20 | private static final long serialVersionUID = 1L; 21 | @ApiModelProperty(value = "自增id", name = "id",required = true) 22 | private Integer id; 23 | @ApiModelProperty(value = " serviceName|Method|URI 资源名称|请求方式|URI (资源地址)", name = "url", required = true) 24 | private String url; 25 | @ApiModelProperty(value = "资源需要权限 多个逗号隔开,且用#隔开 如 ROLE_ADMIN,资源名称|URI|Method (restFul标识)',th/auth/getAuthUser/GET,ROLE_ADMIN 需要GET权限或ROLE_ADMIN角色", name = "needPermission", required = true) 26 | private String needPermission; 27 | @ApiModelProperty(hidden = true) 28 | private Date createTime; 29 | @ApiModelProperty(hidden = true) 30 | private Date updateTime; 31 | @ApiModelProperty(value = "操作用户id", name = "operateId", required = true) 32 | private Integer operateId; 33 | } 34 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/entity/AuthRole.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.entity; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.util.Date; 9 | import java.util.Set; 10 | 11 | /** 12 | * @Description 角色实体 13 | * @Author wwz 14 | * @Date 2019/07/26 15 | * @Param 16 | * @Return 17 | */ 18 | @Data 19 | @ApiModel(value = "AuthRole", description = "角色实体") 20 | public class AuthRole implements Serializable { 21 | private static final long serialVersionUID = 1L; 22 | @ApiModelProperty(value = "自增id", name = "id") 23 | private Integer id; 24 | @ApiModelProperty(value = "角色名称 必须ROLE_开头", name = "roleName", required = true) 25 | private String roleName; 26 | @ApiModelProperty(value = "角色中文名", name = "roleChName", required = true) 27 | private String roleChName; 28 | @ApiModelProperty(value = "是否可用", name = "valid", required = true) 29 | private Boolean valid; 30 | @ApiModelProperty(hidden = true) 31 | private Date createTime; 32 | @ApiModelProperty(hidden = true) 33 | private Date updateTime; 34 | @ApiModelProperty(value = "操作用户id", name = "operateId", required = true) 35 | private Integer operateId; 36 | @ApiModelProperty(hidden = true) 37 | private Set authPermissions; 38 | } 39 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/entity/AuthUser.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.entity; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.util.Date; 9 | import java.util.Set; 10 | 11 | /** 12 | * @Description 用户实体 13 | * @Author wwz 14 | * @Date 2019/07/26 15 | * @Param 16 | * @Return 17 | */ 18 | @Data 19 | @ApiModel(value = "AuthUser", description = "用户实体") 20 | public class AuthUser implements Serializable { 21 | private static final long serialVersionUID = 1L; 22 | @ApiModelProperty(value = "自增id", name = "id") 23 | private Integer id; 24 | @ApiModelProperty(value = "用户名", name = "username", required = true) 25 | private String username; 26 | @ApiModelProperty(value = "密码", name = "password", required = true) 27 | private String password; 28 | @ApiModelProperty(value = "中文名", name = "chName", required = true) 29 | private String chName; 30 | @ApiModelProperty(value = "手机号码", name = "phone", required = true) 31 | private String phone; 32 | @ApiModelProperty(value = "可用性", name = "valid", required = true) 33 | private Boolean valid; 34 | @ApiModelProperty(value = "过期性 true 没过期 false 过期", name = "accountNonExpired", required = true) 35 | private Boolean accountNonExpired; 36 | @ApiModelProperty(value = "有效性", name = "credentialsNonExpired", required = true) 37 | private Boolean credentialsNonExpired; 38 | @ApiModelProperty(value = "锁定性 1未锁定 0锁定", name = "accountNonLocked", required = true) 39 | private Boolean accountNonLocked; 40 | @ApiModelProperty(hidden = true) 41 | private Date createTime; 42 | @ApiModelProperty(hidden = true) 43 | private Date updateTime; 44 | @ApiModelProperty(value = "个人说明", name = "description") 45 | private String description; 46 | @ApiModelProperty(value = "操作用户id", name = "operateId", required = true) 47 | private Integer operateId; 48 | @ApiModelProperty(hidden = true) 49 | private Set authRoles; 50 | } 51 | -------------------------------------------------------------------------------- /fp-commons/src/main/java/com/wwz/frame/entity/OperateLog.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.entity; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * @Description 操作日志 11 | * @Author wwz 12 | * @Date 2019/07/26 13 | * @Param 14 | * @Return 15 | */ 16 | @Data 17 | @ApiModel(value = "OperateLog", description = "操作日志实体") 18 | public class OperateLog { 19 | @ApiModelProperty(hidden = true) 20 | private Integer id; // 自增字段 21 | @ApiModelProperty(value = "操作用户id", name = "operateId", required = true) 22 | private Integer operateId; 23 | @ApiModelProperty(value = "请求地址", name = "remoteAddr", required = true) 24 | private String remoteAddr; 25 | @ApiModelProperty(value = "请求方法", name = "requestUri", required = true) 26 | private String requestUri; 27 | @ApiModelProperty(value = "请求描述", name = "description", required = true) 28 | private String description; 29 | @ApiModelProperty(value = "请求方式", name = "method", required = true) 30 | private String method; 31 | @ApiModelProperty(value = "请求参数", name = "params") 32 | private String params; 33 | @ApiModelProperty(value = "返回值", name = "returnData", required = true) 34 | private String returnData; 35 | @ApiModelProperty(value = "异常信息", name = "exceptionMsg", required = true) 36 | private String exceptionMsg; 37 | @ApiModelProperty(hidden = true) 38 | private Date createTime; // 日志记录时间 39 | } 40 | -------------------------------------------------------------------------------- /fp-gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | SpringCloud-OAuth2-SpringSecurity-Frame 7 | com.wwz.frame 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | fp-gateway 13 | 网关 14 | 15 | 16 | 17 | org.springframework.cloud 18 | spring-cloud-starter-gateway 19 | 20 | 21 | 22 | org.springframework.cloud 23 | spring-cloud-starter-consul-discovery 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-actuator 29 | compile 30 | 31 | 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-maven-plugin 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /fp-gateway/src/main/java/com/wwz/frame/GateWayApplication.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.DiscoveryClient; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator; 8 | import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | @EnableDiscoveryClient 12 | @SpringBootApplication 13 | public class GateWayApplication { 14 | 15 | /** 16 | * 获取注册中心服务设置 17 | * 18 | * @param discoveryClient 19 | * @param properties 20 | * @return 21 | */ 22 | @Bean 23 | public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator( 24 | DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) { 25 | return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties); 26 | } 27 | 28 | public static void main(String[] args) { 29 | SpringApplication.run(GateWayApplication.class, args); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /fp-gateway/src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | #Tomcat 设置最大线程,最小备用线程,端口,请求地址 localhost:8001 2 | server: 3 | tomcat: 4 | max-threads: 100 5 | min-spare-threads: 10 6 | port: 8001 7 | #遇到相同名字是否允许覆盖注册 8 | spring: 9 | main: 10 | allow-bean-definition-overriding: true 11 | application: 12 | name: SpringCloud-consul-gateway 13 | -------------------------------------------------------------------------------- /fp-gateway/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weizongwu/SpringCloud-OAuth2-SpringSecurity-Frame/167412684bcb1d0488dc2e0d860142733964a178/fp-gateway/src/main/resources/application-test.yml -------------------------------------------------------------------------------- /fp-gateway/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #指定为 调用application-dev.xml 2 | spring: 3 | profiles: 4 | active: dev 5 | 6 | 7 | -------------------------------------------------------------------------------- /fp-gateway/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | #port 端口 host 地址 serviceName 注册名称 register:是否注册到consul 默认为false 2 | spring: 3 | cloud: 4 | consul: 5 | port: 8500 6 | host: 192.168.1.130 7 | discovery: 8 | serviceName: gateway 9 | locator: 10 | lower-case-service-id: true 11 | enabled: true 12 | register: true 13 | prefer-ip-address: true #这个必须配 表示使用ip来获取注册,有些网络会出现用主机名来获取注册的问题 14 | tags: version=1.0 15 | health-check-critical-timeout: 60s #多少秒健康检查不过,从consul中删除服务 16 | instance-id: ${spring.application.name}:${spring.cloud.client.ip-address} 17 | health-check-url: http://${spring.cloud.client.ip-address}:${server.port}/actuator/health #设置健康检查路径 18 | -------------------------------------------------------------------------------- /fp-log/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | SpringCloud-OAuth2-SpringSecurity-Frame 7 | com.wwz.frame 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | fp-log 13 | 14 | 15 | -------------------------------------------------------------------------------- /fp-resource-feign/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | SpringCloud-OAuth2-SpringSecurity-Frame 7 | com.wwz.frame 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | fp-resource-feignclient 13 | FeignClient 携带token验证项目 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | 19 | 20 | org.springframework.cloud 21 | spring-cloud-starter-consul-discovery 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-actuator 26 | 27 | 28 | org.projectlombok 29 | lombok 30 | 31 | 32 | com.alibaba 33 | fastjson 34 | 35 | 36 | 37 | org.springframework.cloud 38 | spring-cloud-starter-openfeign 39 | 40 | 41 | com.wwz.frame 42 | fp-commons 43 | 1.0-SNAPSHOT 44 | 45 | 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-maven-plugin 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /fp-resource-feign/src/main/java/com/wwz/frame/FeignClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | import org.springframework.cloud.openfeign.EnableFeignClients; 7 | 8 | /** 9 | * @Description 10 | * @Author wwz 11 | * @Date 2019/11/20 12 | * @Email wwzwtf@qq.com 13 | * @Param 14 | * @Return 15 | */ 16 | @SpringBootApplication 17 | @EnableDiscoveryClient 18 | @EnableFeignClients 19 | public class FeignClientApplication { 20 | public static void main(String[] args) { 21 | SpringApplication.run(FeignClientApplication.class,args); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fp-resource-feign/src/main/java/com/wwz/frame/config/FeignConfig.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import feign.RequestInterceptor; 4 | import feign.RequestTemplate; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.context.request.RequestContextHolder; 7 | import org.springframework.web.context.request.ServletRequestAttributes; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import java.util.Enumeration; 11 | import java.util.LinkedHashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * @Description FeignClient 请求配置器,增加token信息 16 | * @Author wwz 17 | * @Date 2019/11/20 18 | * @Email wwzwtf@qq.com 19 | * @Param 20 | * @Return 21 | */ 22 | @Configuration 23 | public class FeignConfig implements RequestInterceptor { 24 | 25 | public static String TOKEN_HEADER = "authorization"; 26 | 27 | @Override 28 | public void apply(RequestTemplate template) { 29 | template.header(TOKEN_HEADER, getHeaders(getHttpServletRequest()).get(TOKEN_HEADER)); 30 | } 31 | 32 | private HttpServletRequest getHttpServletRequest() { 33 | try { 34 | return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 35 | } catch (Exception e) { 36 | return null; 37 | } 38 | } 39 | 40 | private Map getHeaders(HttpServletRequest request) { 41 | Map map = new LinkedHashMap<>(); 42 | Enumeration enumeration = request.getHeaderNames(); 43 | while (enumeration.hasMoreElements()) { 44 | String key = enumeration.nextElement(); 45 | String value = request.getHeader(key); 46 | map.put(key, value); 47 | } 48 | return map; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /fp-resource-feign/src/main/java/com/wwz/frame/controller/TestFeignClientController.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.controller; 2 | 3 | import com.wwz.frame.feignclient.ResourceManagerFeignClient; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | /** 11 | * @Description FeignClient 测试类 12 | * @Author wwz 13 | * @Date 2019/11/20 14 | * @Email wwzwtf@qq.com 15 | * @Param 16 | * @Return 17 | */ 18 | @RestController 19 | @RequestMapping("feign") 20 | @Slf4j 21 | public class TestFeignClientController { 22 | @Autowired 23 | private ResourceManagerFeignClient resourceManagerFeignClient; 24 | 25 | @GetMapping("hello") 26 | public String hello() { 27 | log.info("进入方法"); 28 | return resourceManagerFeignClient.hello(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /fp-resource-feign/src/main/java/com/wwz/frame/feignclient/ResourceManagerFeignClient.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.feignclient; 2 | 3 | import org.springframework.cloud.openfeign.FeignClient; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | 6 | /** 7 | * @Description FeignClient 调用 fp-resource-manager项目 8 | * @Author wwz 9 | * @Date 2019/11/20 10 | * @Email wwzwtf@qq.com 11 | * @Param 12 | * @Return 13 | */ 14 | @FeignClient(value = "manager") 15 | public interface ResourceManagerFeignClient { 16 | @GetMapping(value = "/auth/hello") 17 | String hello(); 18 | } 19 | -------------------------------------------------------------------------------- /fp-resource-feign/src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | #Tomcat 设置最大线程,最小备用线程,端口,请求地址 localhost:8005 2 | server: 3 | tomcat: 4 | max-threads: 100 5 | min-spare-threads: 10 6 | port: 8005 7 | #遇到相同名字是否允许覆盖注册 8 | spring: 9 | main: 10 | allow-bean-definition-overriding: true 11 | application: 12 | name: SpringCloud-consul-feign 13 | #redis服务器地址配置 14 | redis: 15 | host: 192.168.1.130 16 | port: 6379 -------------------------------------------------------------------------------- /fp-resource-feign/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weizongwu/SpringCloud-OAuth2-SpringSecurity-Frame/167412684bcb1d0488dc2e0d860142733964a178/fp-resource-feign/src/main/resources/application-test.yml -------------------------------------------------------------------------------- /fp-resource-feign/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #指定为 调用application-dev.xml 2 | spring: 3 | profiles: 4 | active: dev 5 | 6 | 7 | -------------------------------------------------------------------------------- /fp-resource-feign/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | #port 端口 host 地址 serviceName 注册名称 register:是否注册到consul 默认为false 2 | spring: 3 | cloud: 4 | consul: 5 | port: 8500 6 | host: 192.168.1.130 7 | discovery: 8 | serviceName: feign 9 | locator: 10 | lower-case-service-id: true 11 | enabled: true 12 | register: true 13 | prefer-ip-address: true #这个必须配 14 | tags: version=1.0 15 | instance-id: ${spring.application.name}:${spring.cloud.client.ip-address} 16 | health-check-critical-timeout: 60s #多少秒健康检查不过,从consul中删除服务 17 | healthCheckInterval: 15s 18 | health-check-url: http://${spring.cloud.client.ip-address}:${server.port}/actuator/health -------------------------------------------------------------------------------- /fp-resource-manager/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | SpringCloud-OAuth2-SpringSecurity-Frame 7 | com.wwz.frame 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | fp-resource-manager 13 | 用户信息管理资源项目 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | 19 | 20 | org.springframework.cloud 21 | spring-cloud-starter-oauth2 22 | 23 | 24 | org.springframework.cloud 25 | spring-cloud-starter-consul-discovery 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-data-redis 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-actuator 34 | 35 | 36 | org.projectlombok 37 | lombok 38 | 39 | 40 | com.alibaba 41 | fastjson 42 | 43 | 44 | 45 | io.springfox 46 | springfox-swagger2 47 | 48 | 49 | 50 | io.springfox 51 | springfox-swagger-ui 52 | 53 | 54 | com.wwz.frame 55 | fp-commons 56 | 1.0-SNAPSHOT 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/AuthManagerApplication.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | 7 | @SpringBootApplication 8 | @EnableDiscoveryClient 9 | public class AuthManagerApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(AuthManagerApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/config/MyAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import com.wwz.frame.common.HttpUtilsResultVO; 4 | import com.wwz.frame.common.ResponseVo; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.security.web.access.AccessDeniedHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | 14 | /** 15 | * @Description 无权访问处理器 16 | * @Author wwz 17 | * @Date 2019/07/30 18 | * @Param 19 | * @Return 20 | */ 21 | @Component 22 | public class MyAccessDeniedHandler implements AccessDeniedHandler { 23 | /** 24 | * Handles an access denied failure. 25 | * 26 | * @param request that resulted in an AccessDeniedException 27 | * @param response so that the user agent can be advised of the failure 28 | * @param accessDeniedException that caused the invocation 29 | * @throws IOException in the event of an IOException 30 | * @throws ServletException in the event of a ServletException 31 | */ 32 | @Override 33 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { 34 | ResponseVo resultVo = new ResponseVo(); 35 | resultVo.setMessage("无权访问!"); 36 | resultVo.setCode(403); 37 | HttpUtilsResultVO.writerError(resultVo, response); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/config/MyFilterInvocationSecurityMetadataSource.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import org.springframework.security.access.ConfigAttribute; 4 | import org.springframework.security.access.SecurityConfig; 5 | import org.springframework.security.web.FilterInvocation; 6 | import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.util.AntPathMatcher; 9 | import org.springframework.util.ObjectUtils; 10 | 11 | import java.util.Collection; 12 | import java.util.HashSet; 13 | import java.util.Set; 14 | 15 | /** 16 | * @Description 根据url获取 url需要访问的权限 17 | * @Author wwz 18 | * @Date 2019/08/01 19 | * @Param 20 | * @Return 21 | */ 22 | @Component 23 | public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { 24 | 25 | private AntPathMatcher antPathMatcher = new AntPathMatcher(); // 模糊匹配 如何 auth/** auth/auth 26 | 27 | @Override 28 | public Collection getAttributes(Object object) throws IllegalArgumentException { 29 | Set set = new HashSet<>(); 30 | 31 | String requestUrl = ((FilterInvocation) object).getRequest().getMethod() + ((FilterInvocation) object).getRequest().getRequestURI(); 32 | System.out.println("requestUrl >> " + requestUrl); 33 | 34 | // 这里获取对比数据可以从数据库或者内存 redis等等地方获取 目前先写死后面优化 35 | String url = "GET/auth/**"; 36 | if (antPathMatcher.match(url, requestUrl)) { 37 | SecurityConfig securityConfig = new SecurityConfig("ROLE_ADMIN"); 38 | set.add(securityConfig); 39 | } 40 | if (ObjectUtils.isEmpty(set)) { 41 | return SecurityConfig.createList("ROLE_LOGIN"); 42 | } 43 | return set; 44 | } 45 | 46 | @Override 47 | public Collection getAllConfigAttributes() { 48 | return null; 49 | } 50 | 51 | @Override 52 | public boolean supports(Class clazz) { 53 | return FilterInvocation.class.isAssignableFrom(clazz); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/config/MySecurityAccessDecisionManager.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import org.springframework.security.access.AccessDecisionManager; 4 | import org.springframework.security.access.AccessDecisionVoter; 5 | import org.springframework.security.access.AccessDeniedException; 6 | import org.springframework.security.access.ConfigAttribute; 7 | import org.springframework.security.authentication.InsufficientAuthenticationException; 8 | import org.springframework.security.core.Authentication; 9 | import org.springframework.security.core.GrantedAuthority; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.util.Collection; 13 | import java.util.List; 14 | 15 | /** 16 | * @Description 自定义权限认证,获取url判断是否有权限 17 | * @Author wwz 18 | * @Date 2019/08/01 19 | * @Param 20 | * @Return 21 | */ 22 | @Component 23 | public class MySecurityAccessDecisionManager implements AccessDecisionManager { 24 | 25 | private List> decisionVoters; 26 | 27 | @Override 28 | public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { 29 | 30 | System.out.println("collection>>" + configAttributes); 31 | 32 | for (ConfigAttribute configAttribute : configAttributes) { 33 | // 当前请求需要的权限 34 | String needRole = configAttribute.getAttribute(); 35 | // 当前用户所具有的权限 36 | Collection authorities = authentication.getAuthorities(); 37 | System.out.println("authorities=" + authorities); 38 | for (GrantedAuthority grantedAuthority : authorities) { 39 | if (grantedAuthority.getAuthority().equals(needRole)) { 40 | return; 41 | } 42 | if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) { 43 | return; 44 | } 45 | 46 | } 47 | } 48 | throw new AccessDeniedException("无访问权限"); 49 | } 50 | 51 | /** 52 | * 复制默认方法,使得@PreAuthorize("hasRole('ROLE_ADMIN')") 可用 53 | */ 54 | @Override 55 | public boolean supports(ConfigAttribute attribute) { 56 | for (AccessDecisionVoter voter : this.decisionVoters) { 57 | if (voter.supports(attribute)) { 58 | return true; 59 | } 60 | } 61 | return false; 62 | } 63 | 64 | @Override 65 | public boolean supports(Class clazz) { 66 | for (AccessDecisionVoter voter : this.decisionVoters) { 67 | if (!voter.supports(clazz)) { 68 | return false; 69 | } 70 | } 71 | return true; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/config/MySecurityResourceServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 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.security.config.annotation.ObjectPostProcessor; 8 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.http.SessionCreationPolicy; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 12 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 13 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 14 | import org.springframework.security.oauth2.provider.token.TokenStore; 15 | import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; 16 | import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; 17 | 18 | import javax.annotation.Resource; 19 | import javax.servlet.http.HttpServletResponse; 20 | 21 | /** 22 | * @Description 资源认证 23 | * @Author wwz 24 | * @Date 2019/08/01 25 | * @Param 26 | * @Return 27 | */ 28 | @Configuration 29 | @EnableResourceServer 30 | @EnableGlobalMethodSecurity(prePostEnabled = true) // 启用注解权限配置 31 | public class MySecurityResourceServerConfig extends ResourceServerConfigurerAdapter { 32 | 33 | @Autowired 34 | private RedisConnectionFactory connectionFactory; 35 | 36 | @Bean 37 | public TokenStore tokenStore() { 38 | RedisTokenStore redis = new RedisTokenStore(connectionFactory); 39 | return redis; 40 | } 41 | 42 | @Resource 43 | private MyAccessDeniedHandler accessDeniedHandler; // 无权访问处理器 44 | 45 | @Resource 46 | private MyTokenExceptionEntryPoint tokenExceptionEntryPoint; // token失效处理器 47 | 48 | @Resource 49 | private MySecurityAccessDecisionManager accessDecisionManager; //权限判断 50 | 51 | @Resource 52 | private MyFilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource; // 请求需要权限 53 | 54 | @Override 55 | public void configure(HttpSecurity http) throws Exception { 56 | http 57 | .csrf().disable() 58 | .exceptionHandling().authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED)) 59 | .and() 60 | .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 另外,如果不设置,那么在通过浏览器访问被保护的任何资源时,每次是不同的SessionID,并且将每次请求的历史都记录在OAuth2Authentication的details的中 61 | .and() 62 | .authorizeRequests().antMatchers("/actuator/health","/v2/api-docs/**", "/swagger-resources/**", "/swagger-ui.html/").permitAll().anyRequest().authenticated() // httpSecurity 放过健康检查,其他都需要验证 设置了.anyRequest().authenticated()才回进入自定义的权限判断 63 | .and() 64 | .requestMatchers().antMatchers("/auth/**", "/authResource/**", "/authUser/**") // .requestMatchers().antMatchers(...) OAuth2设置对资源的保护如果是用 /**的话 会把上面的也拦截掉 65 | .and() 66 | .authorizeRequests() 67 | .withObjectPostProcessor(new ObjectPostProcessor() { // 重写做权限判断 68 | @Override 69 | public O postProcess(O o) { 70 | o.setSecurityMetadataSource(filterInvocationSecurityMetadataSource); // 请求需要权限 71 | o.setAccessDecisionManager(accessDecisionManager); // 权限判断 72 | return o; 73 | } 74 | }) 75 | .and() 76 | .httpBasic(); 77 | 78 | http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); 79 | } 80 | 81 | @Override 82 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 83 | resources.authenticationEntryPoint(tokenExceptionEntryPoint); // token失效处理器 84 | resources.resourceId("manager"); // 设置资源id 通过client的 resource_ids 来判断是否具有资源权限 资源不存在会报Invalid token does not contain resource id (manager) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/config/MyTokenExceptionEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import com.wwz.frame.common.HttpUtilsResultVO; 4 | import com.wwz.frame.common.ResponseVo; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.security.core.AuthenticationException; 7 | import org.springframework.security.web.AuthenticationEntryPoint; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | 15 | /** 16 | * @Description 无效Token返回处理器 17 | * @Author wwz 18 | * @Date 2019/08/01 19 | * @Param 20 | * @Return 21 | */ 22 | @Component 23 | public class MyTokenExceptionEntryPoint implements AuthenticationEntryPoint { 24 | @Override 25 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 26 | Throwable cause = authException.getCause(); 27 | response.setStatus(HttpStatus.OK.value()); 28 | response.setHeader("Content-Type", "application/json;charset=UTF-8"); 29 | try { 30 | HttpUtilsResultVO.writerError(new ResponseVo(401, authException.getMessage()), response); 31 | //response.getWriter().write(JSONObject.toJSONString(new ResultVo(405, "token失效"))); 32 | 33 | } catch (IOException e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 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.OAuthBuilder; 8 | import springfox.documentation.builders.PathSelectors; 9 | import springfox.documentation.builders.RequestHandlerSelectors; 10 | import springfox.documentation.service.*; 11 | import springfox.documentation.spi.DocumentationType; 12 | import springfox.documentation.spi.service.contexts.SecurityContext; 13 | import springfox.documentation.spring.web.plugins.Docket; 14 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 15 | 16 | import java.util.Arrays; 17 | import java.util.Collections; 18 | 19 | /** 20 | * @Description Swagger api 配置 模式二:增加登录 21 | * @Author wwz 22 | * @Date 2019/08/05 23 | */ 24 | @Configuration 25 | @EnableSwagger2 26 | public class SwaggerConfig { 27 | 28 | 29 | @Value("${swagger.is.enable}") 30 | private boolean SWAGGER_IS_ENABLE; //是否激活开关,在application.yml中配置注入 31 | @Value("${swagger.auth.server}") 32 | private String AUTH_SERVER; 33 | @Value("${swagger.service.name}") 34 | private String SERVICE_NAME; 35 | @Bean 36 | public Docket docket() { 37 | return new Docket(DocumentationType.SWAGGER_2) 38 | .enable(SWAGGER_IS_ENABLE) 39 | .apiInfo(apiInfo()) 40 | .select() 41 | .apis(RequestHandlerSelectors.basePackage("com.wwz.frame.controller")) 42 | .paths(PathSelectors.any()) 43 | .build() 44 | // .pathMapping(SERVICE_NAME) 45 | .securitySchemes(Collections.singletonList(securityScheme())) 46 | .securityContexts(Collections.singletonList(securityContext())); 47 | } 48 | 49 | private ApiInfo apiInfo() { 50 | return new ApiInfoBuilder() 51 | // 页面标题 52 | .title("OAuth2权限管理API文档") 53 | .contact(new Contact("wwz", "", "wwzwtf@qq.com")) 54 | .description("OAuth2维护文档") 55 | .version("1.0") 56 | .extensions(Collections.emptyList()) 57 | .build(); 58 | } 59 | 60 | /** 61 | * 这个类决定了你使用哪种认证方式,我这里使用密码模式 62 | */ 63 | private SecurityScheme securityScheme() { 64 | GrantType grantType = new ResourceOwnerPasswordCredentialsGrant(AUTH_SERVER); 65 | 66 | return new OAuthBuilder() 67 | .name("OAuth2") 68 | .grantTypes(Collections.singletonList(grantType)) 69 | .scopes(Arrays.asList(scopes())) 70 | .build(); 71 | } 72 | 73 | /** 74 | * 这里设置 swagger2 认证的安全上下文 75 | */ 76 | private SecurityContext securityContext() { 77 | return SecurityContext.builder() 78 | .securityReferences(Collections.singletonList(new SecurityReference("OAuth2", scopes()))) 79 | .forPaths(PathSelectors.any()) 80 | .build(); 81 | } 82 | 83 | /** 84 | * 这里是写允许认证的scope 85 | */ 86 | private AuthorizationScope[] scopes() { 87 | return new AuthorizationScope[]{ 88 | }; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/config/SwaggerConfig2.java: -------------------------------------------------------------------------------- 1 | //package com.wwz.frame.config; 2 | // 3 | //import org.springframework.beans.factory.annotation.Value; 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.Contact; 13 | //import springfox.documentation.service.Parameter; 14 | //import springfox.documentation.spi.DocumentationType; 15 | //import springfox.documentation.spring.web.plugins.Docket; 16 | //import springfox.documentation.swagger2.annotations.EnableSwagger2; 17 | // 18 | //import java.util.ArrayList; 19 | //import java.util.Collections; 20 | //import java.util.List; 21 | ///** 22 | // * @Description Swagger api 配置 模式一: 增加Authorization 窗口传token 23 | // * @Author wwz 24 | // * @Date 2019/08/05 25 | // */ 26 | //@Configuration 27 | //@EnableSwagger2 28 | //public class SwaggerConfig2 { 29 | // 30 | // @Value("${swagger.is.enable}") 31 | // private boolean SWAGGER_IS_ENABLE; //是否激活开关,在application.yml中配置注入 32 | // 33 | // @Bean 34 | // public Docket docket() { 35 | // //添加head参数配置start 36 | // ParameterBuilder tokenPar = new ParameterBuilder(); 37 | // List pars = new ArrayList<>(); 38 | // tokenPar.name("Authorization").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); 39 | // pars.add(tokenPar.build()); 40 | // return new Docket(DocumentationType.SWAGGER_2) 41 | // .enable(SWAGGER_IS_ENABLE) 42 | // .apiInfo(apiInfo()) 43 | // .select() 44 | // .apis(RequestHandlerSelectors.basePackage("com.wwz.frame.controller")) 45 | // .paths(PathSelectors.any()) 46 | // .build() 47 | // .globalOperationParameters(pars);//注意这里; 48 | // } 49 | // 50 | // private ApiInfo apiInfo() { 51 | // return new ApiInfoBuilder() 52 | // // 页面标题 53 | // .title("OAuth2权限管理API文档") 54 | // .contact(new Contact("wwz", "", "wwzwtf@qq.com")) 55 | // .description("OAuth2维护文档") 56 | // .version("1.0") 57 | // .extensions(Collections.emptyList()) 58 | // .build(); 59 | // } 60 | //} -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/controller/AuthController.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.controller; 2 | 3 | import org.springframework.security.access.prepost.PreAuthorize; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import java.security.Principal; 9 | 10 | @RestController 11 | @RequestMapping("/auth") 12 | public class AuthController { 13 | /** 14 | * 获取用户登陆信息 15 | */ 16 | @GetMapping("/getAuthUser") 17 | public Principal user(Principal authUser) { 18 | return authUser; 19 | } 20 | 21 | @GetMapping("/hello") 22 | @PreAuthorize("hasRole('ROLE_ADMIN')") 23 | public String hello(Principal principal) { 24 | return principal.getName() + " has hello Permission"; 25 | } 26 | 27 | @GetMapping("/world") 28 | public String world() { 29 | return "world"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/controller/AuthResourceController.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.controller; 2 | 3 | import com.wwz.frame.common.ResponseVo; 4 | import com.wwz.frame.entity.AuthResource; 5 | import com.wwz.frame.service.AuthResourceService; 6 | import io.swagger.annotations.Api; 7 | import io.swagger.annotations.ApiImplicitParam; 8 | import io.swagger.annotations.ApiOperation; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.util.List; 13 | 14 | @Api(value = "AuthResourceController", tags = "资源权限配置") 15 | @RestController 16 | @RequestMapping("/authResource") 17 | public class AuthResourceController { 18 | 19 | @Autowired 20 | private AuthResourceService authResourceService; 21 | 22 | @ApiOperation("获取全部资源权限配置信息") 23 | @GetMapping 24 | public ResponseVo getAllAuthResources() { 25 | List list = authResourceService.listAuthResource(); 26 | return new ResponseVo(200, "资源查询成功", list); 27 | } 28 | 29 | @ApiOperation("新建资源配置") 30 | @PostMapping 31 | public ResponseVo saveAuthResource(@RequestBody AuthResource authResource) { 32 | return authResourceService.saveAuthResource(authResource); 33 | } 34 | 35 | @ApiOperation("更新资源配置") 36 | @PutMapping 37 | public ResponseVo updateAuthResource(@RequestBody AuthResource authResource) { 38 | return authResourceService.updateAuthResource(authResource); 39 | } 40 | 41 | @ApiOperation("删除资源配置") 42 | @DeleteMapping 43 | @ApiImplicitParam(name = "id", required = true, value = "资源配置id") 44 | public ResponseVo removeAuthResource(Integer id) { 45 | return authResourceService.removeAuthResource(id); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/controller/AuthUserController.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.controller; 2 | 3 | import com.wwz.frame.common.ResponseVo; 4 | import io.swagger.annotations.Api; 5 | import io.swagger.annotations.ApiOperation; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @Api(value = "AuthUserController", tags = "用户信息配置") 11 | @RestController 12 | @RequestMapping("/authUser") 13 | public class AuthUserController { 14 | 15 | @ApiOperation("获取全部用户信息") 16 | @GetMapping 17 | public ResponseVo getAllAuthUser() { 18 | return new ResponseVo(200, "资源查询成功"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/service/AuthResourceService.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.service; 2 | 3 | import com.wwz.frame.common.ResponseVo; 4 | import com.wwz.frame.entity.AuthResource; 5 | 6 | import java.util.List; 7 | 8 | 9 | public interface AuthResourceService { 10 | /** 11 | * 获取全部 12 | */ 13 | List listAuthResource(); 14 | 15 | /** 16 | * 新建 资源权限 17 | */ 18 | ResponseVo saveAuthResource(AuthResource authResource); 19 | 20 | /** 21 | * 更新 资源权限 22 | */ 23 | ResponseVo updateAuthResource(AuthResource authResource); 24 | 25 | /** 26 | * 删除 资源权限 27 | */ 28 | ResponseVo removeAuthResource(Integer id); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/service/MyUserDetails.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.service; 2 | 3 | import com.wwz.frame.entity.AuthUser; 4 | import lombok.Data; 5 | import org.springframework.security.core.GrantedAuthority; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | 8 | import java.util.Collection; 9 | 10 | /** 11 | * @Description 自定义实现UserDetails 资源服务器中用于redis反序列化用户信息 12 | * @Author wwz 13 | * @Date 2019/08/01 14 | * @Param 15 | * @Return 16 | */ 17 | @Data 18 | public class MyUserDetails implements UserDetails { 19 | private AuthUser user; 20 | 21 | private Collection authorities; 22 | 23 | public MyUserDetails(AuthUser user, Collection authorities) { 24 | this.user = user; 25 | this.authorities = authorities; 26 | } 27 | 28 | public MyUserDetails() { 29 | } 30 | 31 | @Override 32 | public Collection getAuthorities() { 33 | return authorities; 34 | } 35 | 36 | @Override 37 | public String getPassword() { 38 | return user.getPassword(); 39 | } 40 | 41 | @Override 42 | public String getUsername() { 43 | return user.getUsername(); 44 | } 45 | 46 | @Override 47 | public boolean isAccountNonExpired() { 48 | return user.getAccountNonExpired(); 49 | } 50 | 51 | @Override 52 | public boolean isAccountNonLocked() { 53 | return user.getAccountNonLocked(); 54 | } 55 | 56 | @Override 57 | public boolean isCredentialsNonExpired() { 58 | return user.getCredentialsNonExpired(); 59 | } 60 | 61 | @Override 62 | public boolean isEnabled() { 63 | return user.getValid(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/service/impl/AuthResourceServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.service.impl; 2 | 3 | import com.wwz.frame.common.ResponseVo; 4 | import com.wwz.frame.entity.AuthResource; 5 | import com.wwz.frame.service.AuthResourceService; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.List; 9 | 10 | @Service 11 | public class AuthResourceServiceImpl implements AuthResourceService { 12 | @Override 13 | public List listAuthResource() { 14 | return null; 15 | } 16 | 17 | @Override 18 | public ResponseVo saveAuthResource(AuthResource authResource) { 19 | return null; 20 | } 21 | 22 | @Override 23 | public ResponseVo updateAuthResource(AuthResource authResource) { 24 | return null; 25 | } 26 | 27 | @Override 28 | public ResponseVo removeAuthResource(Integer id) { 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/token/MyAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.token; 2 | 3 | import org.springframework.security.authentication.AbstractAuthenticationToken; 4 | import org.springframework.security.core.GrantedAuthority; 5 | 6 | import java.util.Collection; 7 | 8 | /** 9 | * @Description 自定义AbstractAuthenticationToken 10 | * @Author wwz 11 | * @Date 2019/08/04 12 | * @Param 13 | * @Return 14 | */ 15 | public class MyAuthenticationToken extends AbstractAuthenticationToken { 16 | 17 | private static final long serialVersionUID = 110L; 18 | protected final Object principal; 19 | protected Object credentials; 20 | 21 | /** 22 | * This constructor can be safely used by any code that wishes to create a 23 | * UsernamePasswordAuthenticationToken, as the {@link 24 | * #isAuthenticated()} will return false. 25 | * 26 | */ 27 | public MyAuthenticationToken(Object principal, Object credentials) { 28 | super(null); 29 | this.principal = principal; 30 | this.credentials = credentials; 31 | this.setAuthenticated(false); 32 | } 33 | 34 | /** 35 | * This constructor should only be used by AuthenticationManager or AuthenticationProvider 36 | * implementations that are satisfied with producing a trusted (i.e. {@link #isAuthenticated()} = true) 37 | * token token. 38 | * 39 | * @param principal 40 | * @param credentials 41 | * @param authorities 42 | */ 43 | public MyAuthenticationToken(Object principal, Object credentials, Collection authorities) { 44 | super(authorities); 45 | this.principal = principal; 46 | this.credentials = credentials; 47 | super.setAuthenticated(true); 48 | } 49 | 50 | 51 | @Override 52 | public Object getCredentials() { 53 | return this.credentials; 54 | } 55 | 56 | @Override 57 | public Object getPrincipal() { 58 | return this.principal; 59 | } 60 | 61 | 62 | public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { 63 | if(isAuthenticated) { 64 | throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); 65 | } else { 66 | super.setAuthenticated(false); 67 | } 68 | } 69 | 70 | public void eraseCredentials() { 71 | super.eraseCredentials(); 72 | this.credentials = null; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/java/com/wwz/frame/token/MyPhoneAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package com.wwz.frame.token; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | 5 | import java.util.Collection; 6 | 7 | /** 8 | * @Description 手机验证token 9 | * @Author wwz 10 | * @Date 2019/08/04 11 | * @Param 12 | * @Return 13 | */ 14 | public class MyPhoneAuthenticationToken extends MyAuthenticationToken { 15 | 16 | public MyPhoneAuthenticationToken(Object principal, Object credentials) { 17 | super(principal, credentials); 18 | } 19 | 20 | public MyPhoneAuthenticationToken(Object principal, Object credentials, Collection authorities) { 21 | super(principal, credentials, authorities); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | #Tomcat 设置最大线程,最小备用线程,端口,请求地址 localhost:8004 2 | server: 3 | tomcat: 4 | max-threads: 100 5 | min-spare-threads: 10 6 | port: 8004 7 | #遇到相同名字是否允许覆盖注册 8 | spring: 9 | main: 10 | allow-bean-definition-overriding: true 11 | application: 12 | name: SpringCloud-consul-authorization-manager 13 | #redis服务器地址配置 14 | redis: 15 | host: 192.168.1.130 16 | port: 6379 17 | #swagger 配置 18 | swagger: 19 | is: 20 | enable: true #是否开启swagger 21 | auth: 22 | server: http://192.168.3.14:8001/auth/oauth/token #验证token请求地址:ip+网关+服务名称+请求地址 23 | service: 24 | name: manager -------------------------------------------------------------------------------- /fp-resource-manager/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weizongwu/SpringCloud-OAuth2-SpringSecurity-Frame/167412684bcb1d0488dc2e0d860142733964a178/fp-resource-manager/src/main/resources/application-test.yml -------------------------------------------------------------------------------- /fp-resource-manager/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #指定为 调用application-dev.xml 2 | spring: 3 | profiles: 4 | active: dev 5 | 6 | 7 | -------------------------------------------------------------------------------- /fp-resource-manager/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | #port 端口 host 地址 serviceName 注册名称 register:是否注册到consul 默认为false 2 | spring: 3 | cloud: 4 | consul: 5 | port: 8500 6 | host: 192.168.1.130 7 | discovery: 8 | serviceName: manager 9 | locator: 10 | lower-case-service-id: true 11 | enabled: true 12 | register: true 13 | prefer-ip-address: true #这个必须配 14 | tags: version=1.0 15 | instance-id: ${spring.application.name}:${spring.cloud.client.ip-address} 16 | health-check-critical-timeout: 60s #多少秒健康检查不过,从consul中删除服务 17 | healthCheckInterval: 15s #检查间隔 18 | health-check-url: http://${spring.cloud.client.ip-address}:${server.port}/actuator/health 19 | -------------------------------------------------------------------------------- /frame-permission.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : my 5 | Source Server Version : 50721 6 | Source Host : localhost:3306 7 | Source Database : frame-permission 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50721 11 | File Encoding : 65001 12 | 13 | Date: 2019-08-05 10:40:46 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for `auth_client_details` 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `auth_client_details`; 22 | CREATE TABLE `auth_client_details` ( 23 | `id` int(11) NOT NULL AUTO_INCREMENT, 24 | `client_id` varchar(64) DEFAULT NULL, 25 | `client_secret` varchar(255) DEFAULT NULL, 26 | `resource_ids` varchar(255) DEFAULT NULL, 27 | `scopes` varchar(255) DEFAULT NULL, 28 | `authorized_grant_types` varchar(255) DEFAULT NULL, 29 | `web_server_redirect_uris` varchar(255) DEFAULT NULL, 30 | `authorities` varchar(255) DEFAULT NULL, 31 | `access_token_validity` int(11) DEFAULT NULL, 32 | `refresh_token_validity` int(11) DEFAULT NULL, 33 | `additional_information` varchar(255) DEFAULT NULL, 34 | `auto_approve` varchar(255) DEFAULT NULL, 35 | `valid` tinyint(4) DEFAULT NULL COMMENT '可用性 1是 0否', 36 | PRIMARY KEY (`id`), 37 | UNIQUE KEY `pk_client_id` (`client_id`) USING BTREE 38 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='OAuth2自带表'; 39 | 40 | -- ---------------------------- 41 | -- Records of auth_client_details 42 | -- ---------------------------- 43 | INSERT INTO `auth_client_details` VALUES ('1', 'client_name', '$2a$10$NaVQghEKxZHQskPC69eyte3iuwYZsLs/rGfSt0Kgt1QQ/k2esoLxu', 'auth,manager', 'auth,manager', 'password,authorization_code,refresh_token,client_credentials', 'http://192.168.3.14:8001/auth/oauth/token', '', '3600', '36000', null, 'false', null); 44 | 45 | -- ---------------------------- 46 | -- Table structure for `auth_permission` 47 | -- ---------------------------- 48 | DROP TABLE IF EXISTS `auth_permission`; 49 | CREATE TABLE `auth_permission` ( 50 | `id` int(11) NOT NULL AUTO_INCREMENT, 51 | `permission_name` varchar(50) DEFAULT NULL COMMENT '权限名称', 52 | `service_prefix` varchar(25) DEFAULT NULL COMMENT '前缀', 53 | `method` varchar(10) DEFAULT NULL COMMENT '请求方式 restful 模式 GET查看 POST 新增 PUT更新 DELETE 删除', 54 | `uri` varchar(50) DEFAULT NULL COMMENT '请求地址 资源', 55 | `valid` tinyint(4) DEFAULT NULL COMMENT '是否可用1是0否', 56 | `create_time` date DEFAULT NULL COMMENT '创建时间', 57 | `update_time` date DEFAULT NULL COMMENT '更新时间', 58 | `operate_id` int(11) DEFAULT NULL COMMENT '操作用户id', 59 | PRIMARY KEY (`id`) 60 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='权限表'; 61 | 62 | -- ---------------------------- 63 | -- Records of auth_permission 64 | -- ---------------------------- 65 | INSERT INTO `auth_permission` VALUES ('1', '查看auth服务用户权限', 'auth', 'GET', 'auth/getAuthUser', '1', '2019-07-07', '2019-07-07', null); 66 | INSERT INTO `auth_permission` VALUES ('2', '查看auth服务hello权限', 'auth', 'GET', 'auth/hello', '1', '2019-07-07', '2019-07-07', null); 67 | INSERT INTO `auth_permission` VALUES ('3', '查看api服务hello权限', 'api', 'GET', 'hello', '1', '2019-07-07', '2019-07-07', null); 68 | 69 | -- ---------------------------- 70 | -- Table structure for `auth_resource` 71 | -- ---------------------------- 72 | DROP TABLE IF EXISTS `auth_resource`; 73 | CREATE TABLE `auth_resource` ( 74 | `id` int(11) NOT NULL AUTO_INCREMENT, 75 | `url` varchar(255) DEFAULT NULL COMMENT 'serviceName|Method|URI 资源名称|请求方式|URI (资源地址)', 76 | `need_permission` varchar(255) DEFAULT NULL COMMENT '资源需要权限 多个逗号隔开,且用#隔开 如 ROLE_ADMIN,资源名称|URI|Method (restFul标识)', 77 | `create_time` date DEFAULT NULL, 78 | `update_time` date DEFAULT NULL, 79 | `operate_id` int(11) DEFAULT NULL COMMENT '操作用户id', 80 | PRIMARY KEY (`id`) 81 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权限配置表'; 82 | 83 | -- ---------------------------- 84 | -- Records of auth_resource 85 | -- ---------------------------- 86 | 87 | -- ---------------------------- 88 | -- Table structure for `auth_role` 89 | -- ---------------------------- 90 | DROP TABLE IF EXISTS `auth_role`; 91 | CREATE TABLE `auth_role` ( 92 | `id` int(11) NOT NULL AUTO_INCREMENT, 93 | `role_name` varchar(50) DEFAULT NULL COMMENT '角色名称', 94 | `role_ch_name` varchar(50) DEFAULT NULL COMMENT '角色中文名', 95 | `valid` tinyint(4) DEFAULT NULL COMMENT '是否可用1是0否', 96 | `create_time` date DEFAULT NULL COMMENT '创建时间', 97 | `update_time` date DEFAULT NULL COMMENT '更新时间', 98 | `operate_id` int(11) DEFAULT NULL COMMENT '操作用户id', 99 | PRIMARY KEY (`id`), 100 | UNIQUE KEY `rn_unique` (`role_name`) USING BTREE 101 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 102 | 103 | -- ---------------------------- 104 | -- Records of auth_role 105 | -- ---------------------------- 106 | INSERT INTO `auth_role` VALUES ('1', 'ROLE_ADMIN', '超级管理员', '1', '2019-07-07', '2019-07-07', null); 107 | 108 | -- ---------------------------- 109 | -- Table structure for `auth_role_permission` 110 | -- ---------------------------- 111 | DROP TABLE IF EXISTS `auth_role_permission`; 112 | CREATE TABLE `auth_role_permission` ( 113 | `id` int(11) NOT NULL AUTO_INCREMENT, 114 | `auth_role_id` int(11) NOT NULL COMMENT '角色id', 115 | `auth_permission_id` int(11) NOT NULL COMMENT '用户id', 116 | `create_time` date DEFAULT NULL, 117 | `update_time` date DEFAULT NULL, 118 | `valid` tinyint(4) DEFAULT NULL COMMENT '是否可用', 119 | `operate_id` int(11) NOT NULL COMMENT '操作用户id', 120 | PRIMARY KEY (`id`) 121 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='角色-权限关联表'; 122 | 123 | -- ---------------------------- 124 | -- Records of auth_role_permission 125 | -- ---------------------------- 126 | INSERT INTO `auth_role_permission` VALUES ('1', '1', '1', '2019-07-07', '2019-07-07', '1', '1'); 127 | INSERT INTO `auth_role_permission` VALUES ('2', '1', '2', '2019-07-07', '2019-07-07', '1', '1'); 128 | INSERT INTO `auth_role_permission` VALUES ('3', '1', '3', '2019-07-07', '2019-07-07', '1', '1'); 129 | 130 | -- ---------------------------- 131 | -- Table structure for `auth_user` 132 | -- ---------------------------- 133 | DROP TABLE IF EXISTS `auth_user`; 134 | CREATE TABLE `auth_user` ( 135 | `id` int(11) NOT NULL AUTO_INCREMENT, 136 | `username` varchar(50) NOT NULL COMMENT '用户名', 137 | `password` varchar(100) NOT NULL COMMENT '密码', 138 | `phone` varchar(11) DEFAULT NULL, 139 | `ch_name` varchar(50) DEFAULT NULL COMMENT '中文名', 140 | `valid` tinyint(4) DEFAULT NULL COMMENT '可用性', 141 | `account_non_expired` tinyint(4) DEFAULT NULL COMMENT '过期性 1没过期0过期', 142 | `credentials_non_expired` tinyint(4) DEFAULT NULL COMMENT '有效性 1有效0失效', 143 | `account_non_locked` tinyint(4) DEFAULT NULL COMMENT '锁定性 1未锁定0锁定', 144 | `create_time` date DEFAULT NULL COMMENT '创建时间', 145 | `update_time` date DEFAULT NULL COMMENT '更新时间', 146 | `description` varchar(255) DEFAULT NULL COMMENT '个人说明', 147 | `operate_id` int(11) DEFAULT NULL COMMENT '操作用户id', 148 | PRIMARY KEY (`id`), 149 | UNIQUE KEY `un_u` (`username`) USING BTREE, 150 | UNIQUE KEY `un_phone` (`phone`) USING BTREE 151 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户表'; 152 | 153 | -- ---------------------------- 154 | -- Records of auth_user 155 | -- ---------------------------- 156 | INSERT INTO `auth_user` VALUES ('1', 'username', '$2a$10$NaVQghEKxZHQskPC69eyte3iuwYZsLs/rGfSt0Kgt1QQ/k2esoLxu', '15000000000', '管理员', '1', '1', '1', '1', '2019-07-07', '2019-07-07', null, null); 157 | 158 | -- ---------------------------- 159 | -- Table structure for `auth_user_role` 160 | -- ---------------------------- 161 | DROP TABLE IF EXISTS `auth_user_role`; 162 | CREATE TABLE `auth_user_role` ( 163 | `id` int(11) NOT NULL AUTO_INCREMENT, 164 | `auth_user_id` int(11) NOT NULL COMMENT '用户id', 165 | `auth_role_id` int(11) NOT NULL COMMENT '角色id', 166 | `create_time` date DEFAULT NULL, 167 | `update_time` date DEFAULT NULL, 168 | `valid` tinyint(4) DEFAULT NULL COMMENT '是否可用', 169 | `operate_id` int(11) DEFAULT NULL COMMENT '操作用户id', 170 | PRIMARY KEY (`id`) 171 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户-角色关联表'; 172 | 173 | -- ---------------------------- 174 | -- Records of auth_user_role 175 | -- ---------------------------- 176 | INSERT INTO `auth_user_role` VALUES ('1', '1', '1', '2019-07-07', '2019-07-07', '1', null); 177 | 178 | -- ---------------------------- 179 | -- Table structure for `operate_log` 180 | -- ---------------------------- 181 | DROP TABLE IF EXISTS `operate_log`; 182 | CREATE TABLE `operate_log` ( 183 | `id` int(11) NOT NULL AUTO_INCREMENT, 184 | `operate_id` int(11) DEFAULT NULL COMMENT '操作用户id', 185 | `remote_addr` varchar(100) DEFAULT NULL COMMENT '请求地址', 186 | `request_uri` varchar(100) DEFAULT NULL COMMENT '请求方法', 187 | `description` varchar(255) DEFAULT NULL COMMENT '请求描述', 188 | `method` varchar(25) DEFAULT NULL COMMENT '请求方式', 189 | `params` varchar(255) DEFAULT NULL COMMENT '请求参数', 190 | `return_data` varchar(255) DEFAULT NULL COMMENT '返回值', 191 | `exception_msg` varchar(100) DEFAULT NULL COMMENT '异常信息', 192 | `create_time` date DEFAULT NULL COMMENT '日志记录时间', 193 | PRIMARY KEY (`id`) 194 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='操作日志'; 195 | 196 | -- ---------------------------- 197 | -- Records of operate_log 198 | -- ---------------------------- 199 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.wwz.frame 8 | SpringCloud-OAuth2-SpringSecurity-Frame 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | fp-commons 13 | fp-gateway 14 | fp-resource-manager 15 | fp-authorization-server 16 | fp-log 17 | fp-resource-feign 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-parent 23 | 2.1.0.RELEASE 24 | 25 | 26 | 27 | UTF-8 28 | 1.8 29 | Greenwich.SR2 30 | 2.6 31 | 1.1.10 32 | 1.2.49 33 | 1.16.22 34 | 2.8.0 35 | 23.0 36 | 5.1.47 37 | 1.3.2 38 | 1.2.5 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.springframework.cloud 46 | spring-cloud-dependencies 47 | ${spring-cloud.version} 48 | pom 49 | import 50 | 51 | 52 | 53 | com.alibaba 54 | druid 55 | ${druid.version} 56 | 57 | 58 | 59 | org.projectlombok 60 | lombok 61 | true 62 | ${lombok.version} 63 | 64 | 65 | 66 | com.alibaba 67 | fastjson 68 | ${fastjson.version} 69 | 70 | 71 | commons-lang 72 | commons-lang 73 | ${commons.lang.version} 74 | 75 | 76 | 77 | com.google.guava 78 | guava 79 | ${guava.version} 80 | 81 | 82 | 83 | io.springfox 84 | springfox-swagger2 85 | ${springfox-swagger2.version} 86 | 87 | 88 | 89 | io.springfox 90 | springfox-swagger-ui 91 | ${springfox-swagger2.version} 92 | 93 | 94 | 95 | org.mybatis.spring.boot 96 | mybatis-spring-boot-starter 97 | ${mybatis.version} 98 | 99 | 100 | 101 | mysql 102 | mysql-connector-java 103 | ${mysql.version} 104 | 105 | 106 | 107 | com.github.pagehelper 108 | pagehelper-spring-boot-starter 109 | ${pageHelper.version} 110 | 111 | 112 | 113 | org.mybatis.generator 114 | mybatis-generator-core 115 | 1.3.1 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | org.springframework.boot 124 | spring-boot-maven-plugin 125 | 126 | 127 | 128 | --------------------------------------------------------------------------------