Commit 3351ebbbb4ea4971a6fde9d0b9ba97913cc46137

Authored by YunaiV
1 parent baadb5a9

去除 Spring Security 的 logout handler,使用自己定义的 logout 接口

Showing 14 changed files with 342 additions and 66 deletions
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java
@@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocal @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocal
6 import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; 6 import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter;
7 import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; 7 import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl;
8 import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; 8 import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl;
9 -import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl;  
10 import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; 9 import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
11 import cn.iocoder.yudao.framework.web.config.WebProperties; 10 import cn.iocoder.yudao.framework.web.config.WebProperties;
12 import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; 11 import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
@@ -19,7 +18,6 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -19,7 +18,6 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
19 import org.springframework.security.crypto.password.PasswordEncoder; 18 import org.springframework.security.crypto.password.PasswordEncoder;
20 import org.springframework.security.web.AuthenticationEntryPoint; 19 import org.springframework.security.web.AuthenticationEntryPoint;
21 import org.springframework.security.web.access.AccessDeniedHandler; 20 import org.springframework.security.web.access.AccessDeniedHandler;
22 -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;  
23 21
24 import javax.annotation.Resource; 22 import javax.annotation.Resource;
25 import java.util.List; 23 import java.util.List;
@@ -64,14 +62,6 @@ public class YudaoSecurityAutoConfiguration { @@ -64,14 +62,6 @@ public class YudaoSecurityAutoConfiguration {
64 } 62 }
65 63
66 /** 64 /**
67 - * 退出处理类 Bean  
68 - */  
69 - @Bean  
70 - public LogoutSuccessHandler logoutSuccessHandler(MultiUserDetailsAuthenticationProvider authenticationProvider) {  
71 - return new LogoutSuccessHandlerImpl(securityProperties, authenticationProvider);  
72 - }  
73 -  
74 - /**  
75 * Spring Security 加密器 65 * Spring Security 加密器
76 * 考虑到安全性,这里采用 BCryptPasswordEncoder 加密器 66 * 考虑到安全性,这里采用 BCryptPasswordEncoder 加密器
77 * 67 *
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
1 package cn.iocoder.yudao.framework.security.config; 1 package cn.iocoder.yudao.framework.security.config;
2 2
3 -import cn.hutool.core.util.StrUtil;  
4 import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider; 3 import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;
5 import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; 4 import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter;
6 import cn.iocoder.yudao.framework.web.config.WebProperties; 5 import cn.iocoder.yudao.framework.web.config.WebProperties;
@@ -17,7 +16,6 @@ import org.springframework.security.config.http.SessionCreationPolicy; @@ -17,7 +16,6 @@ import org.springframework.security.config.http.SessionCreationPolicy;
17 import org.springframework.security.web.AuthenticationEntryPoint; 16 import org.springframework.security.web.AuthenticationEntryPoint;
18 import org.springframework.security.web.access.AccessDeniedHandler; 17 import org.springframework.security.web.access.AccessDeniedHandler;
19 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 18 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
20 -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;  
21 19
22 import javax.annotation.Resource; 20 import javax.annotation.Resource;
23 import java.util.List; 21 import java.util.List;
@@ -47,11 +45,6 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap @@ -47,11 +45,6 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
47 @Resource 45 @Resource
48 private AccessDeniedHandler accessDeniedHandler; 46 private AccessDeniedHandler accessDeniedHandler;
49 /** 47 /**
50 - * 退出处理类 Bean  
51 - */  
52 - @Resource  
53 - private LogoutSuccessHandler logoutSuccessHandler;  
54 - /**  
55 * Token 认证过滤器 Bean 48 * Token 认证过滤器 Bean
56 */ 49 */
57 @Resource 50 @Resource
@@ -114,11 +107,8 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap @@ -114,11 +107,8 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap
114 .headers().frameOptions().disable().and() 107 .headers().frameOptions().disable().and()
115 // 一堆自定义的 Spring Security 处理器 108 // 一堆自定义的 Spring Security 处理器
116 .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint) 109 .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
117 - .accessDeniedHandler(accessDeniedHandler).and()  
118 - // 登出地址的配置  
119 - .logout().logoutSuccessHandler(logoutSuccessHandler).logoutRequestMatcher(request -> // 匹配多种用户类型的登出  
120 - StrUtil.equalsAny(request.getRequestURI(), buildAdminApi("/system/logout"),  
121 - buildAppApi("/member/logout"))); 110 + .accessDeniedHandler(accessDeniedHandler);
  111 + // 登录、登录暂时不使用 Spring Security 的拓展点,主要考虑一方面拓展多用户、多种登录方式相对复杂,一方面用户的学习成本较高
122 112
123 // 设置每个请求的权限 113 // 设置每个请求的权限
124 httpSecurity 114 httpSecurity
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java deleted
1 -package cn.iocoder.yudao.framework.security.core.handler;  
2 -  
3 -import cn.hutool.core.util.StrUtil;  
4 -import cn.iocoder.yudao.framework.common.pojo.CommonResult;  
5 -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;  
6 -import cn.iocoder.yudao.framework.security.config.SecurityProperties;  
7 -import cn.iocoder.yudao.framework.security.core.authentication.MultiUserDetailsAuthenticationProvider;  
8 -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;  
9 -import lombok.AllArgsConstructor;  
10 -import org.springframework.security.core.Authentication;  
11 -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;  
12 -  
13 -import javax.servlet.http.HttpServletRequest;  
14 -import javax.servlet.http.HttpServletResponse;  
15 -  
16 -  
17 -/**  
18 - * 自定义退出处理器  
19 - *  
20 - * @author ruoyi  
21 - */  
22 -@AllArgsConstructor  
23 -public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {  
24 -  
25 - private final SecurityProperties securityProperties;  
26 -  
27 - private final MultiUserDetailsAuthenticationProvider authenticationProvider;  
28 -  
29 - @Override  
30 - public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {  
31 - // 执行退出  
32 - String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());  
33 - if (StrUtil.isNotBlank(token)) {  
34 - authenticationProvider.logout(request, token);  
35 - }  
36 - // 返回成功  
37 - ServletUtils.writeJSON(response, CommonResult.success(null));  
38 - }  
39 -  
40 -}  
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java
1 package cn.iocoder.yudao.module.member.controller.app.auth; 1 package cn.iocoder.yudao.module.member.controller.app.auth;
2 2
  3 +import cn.hutool.core.util.StrUtil;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.security.config.SecurityProperties;
4 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; 6 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
  7 +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
5 import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; 8 import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
6 import cn.iocoder.yudao.module.member.service.auth.MemberAuthService; 9 import cn.iocoder.yudao.module.member.service.auth.MemberAuthService;
7 import io.swagger.annotations.Api; 10 import io.swagger.annotations.Api;
@@ -13,6 +16,7 @@ import org.springframework.validation.annotation.Validated; @@ -13,6 +16,7 @@ import org.springframework.validation.annotation.Validated;
13 import org.springframework.web.bind.annotation.*; 16 import org.springframework.web.bind.annotation.*;
14 17
15 import javax.annotation.Resource; 18 import javax.annotation.Resource;
  19 +import javax.servlet.http.HttpServletRequest;
16 import javax.validation.Valid; 20 import javax.validation.Valid;
17 21
18 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 22 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -30,6 +34,9 @@ public class AppAuthController { @@ -30,6 +34,9 @@ public class AppAuthController {
30 @Resource 34 @Resource
31 private MemberAuthService authService; 35 private MemberAuthService authService;
32 36
  37 + @Resource
  38 + private SecurityProperties securityProperties;
  39 +
33 @PostMapping("/login") 40 @PostMapping("/login")
34 @ApiOperation("使用手机 + 密码登录") 41 @ApiOperation("使用手机 + 密码登录")
35 public CommonResult<AppAuthLoginRespVO> login(@RequestBody @Valid AppAuthLoginReqVO reqVO) { 42 public CommonResult<AppAuthLoginRespVO> login(@RequestBody @Valid AppAuthLoginReqVO reqVO) {
@@ -37,6 +44,16 @@ public class AppAuthController { @@ -37,6 +44,16 @@ public class AppAuthController {
37 return success(AppAuthLoginRespVO.builder().token(token).build()); 44 return success(AppAuthLoginRespVO.builder().token(token).build());
38 } 45 }
39 46
  47 + @PostMapping("/logout")
  48 + @ApiOperation("登出系统")
  49 + public CommonResult<Boolean> logout(HttpServletRequest request) {
  50 + String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
  51 + if (StrUtil.isNotBlank(token)) {
  52 + authService.logout(token);
  53 + }
  54 + return success(true);
  55 + }
  56 +
40 @PostMapping("/sms-login") 57 @PostMapping("/sms-login")
41 @ApiOperation("使用手机 + 验证码登录") 58 @ApiOperation("使用手机 + 验证码登录")
42 public CommonResult<AppAuthLoginRespVO> smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) { 59 public CommonResult<AppAuthLoginRespVO> smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) {
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/package-info.java 0 → 100644
  1 +/**
  2 + * 属于 system 模块的 framework 封装
  3 + *
  4 + * @author 芋道源码
  5 + */
  6 +package cn.iocoder.yudao.module.member.framework;
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/security/config/SecurityConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.framework.security.config;
  2 +
  3 +import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
  4 +import org.springframework.context.annotation.Bean;
  5 +import org.springframework.context.annotation.Configuration;
  6 +import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  7 +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
  8 +
  9 +/**
  10 + * Member 模块的 Security 配置
  11 + */
  12 +@Configuration("memberSecurityConfiguration")
  13 +public class SecurityConfiguration {
  14 +
  15 + @Bean("memberAuthorizeRequestsCustomizer")
  16 + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
  17 + return new AuthorizeRequestsCustomizer() {
  18 +
  19 + @Override
  20 + public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
  21 + // 登录的接口
  22 + registry.antMatchers(buildAdminApi("/member/auth/logout")).permitAll();
  23 + }
  24 +
  25 + };
  26 + }
  27 +
  28 +}
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/security/core/package-info.java 0 → 100644
  1 +/**
  2 + * 占位
  3 + */
  4 +package cn.iocoder.yudao.module.member.framework.security.core;
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
1 package cn.iocoder.yudao.module.system.controller.admin.auth; 1 package cn.iocoder.yudao.module.system.controller.admin.auth;
2 2
  3 +import cn.hutool.core.util.StrUtil;
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.util.collection.SetUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
6 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; 7 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  8 +import cn.iocoder.yudao.framework.security.config.SecurityProperties;
  9 +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
7 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*; 10 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
8 import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; 11 import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
9 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; 12 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
@@ -24,6 +27,7 @@ import org.springframework.validation.annotation.Validated; @@ -24,6 +27,7 @@ import org.springframework.validation.annotation.Validated;
24 import org.springframework.web.bind.annotation.*; 27 import org.springframework.web.bind.annotation.*;
25 28
26 import javax.annotation.Resource; 29 import javax.annotation.Resource;
  30 +import javax.servlet.http.HttpServletRequest;
27 import javax.validation.Valid; 31 import javax.validation.Valid;
28 import java.util.List; 32 import java.util.List;
29 import java.util.Set; 33 import java.util.Set;
@@ -52,15 +56,28 @@ public class AuthController { @@ -52,15 +56,28 @@ public class AuthController {
52 @Resource 56 @Resource
53 private SocialUserService socialUserService; 57 private SocialUserService socialUserService;
54 58
  59 + @Resource
  60 + private SecurityProperties securityProperties;
  61 +
55 @PostMapping("/login") 62 @PostMapping("/login")
56 @ApiOperation("使用账号密码登录") 63 @ApiOperation("使用账号密码登录")
57 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 64 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
58 public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) { 65 public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
59 String token = authService.login(reqVO, getClientIP(), getUserAgent()); 66 String token = authService.login(reqVO, getClientIP(), getUserAgent());
60 - // 返回结果  
61 return success(AuthLoginRespVO.builder().token(token).build()); 67 return success(AuthLoginRespVO.builder().token(token).build());
62 } 68 }
63 69
  70 + @PostMapping("/logout")
  71 + @ApiOperation("登出系统")
  72 + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
  73 + public CommonResult<Boolean> logout(HttpServletRequest request) {
  74 + String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
  75 + if (StrUtil.isNotBlank(token)) {
  76 + authService.logout(token);
  77 + }
  78 + return success(true);
  79 + }
  80 +
64 @GetMapping("/get-permission-info") 81 @GetMapping("/get-permission-info")
65 @ApiOperation("获取登录用户的权限信息") 82 @ApiOperation("获取登录用户的权限信息")
66 public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() { 83 public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
@@ -130,7 +147,6 @@ public class AuthController { @@ -130,7 +147,6 @@ public class AuthController {
130 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 147 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
131 public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialQuickLoginReqVO reqVO) { 148 public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialQuickLoginReqVO reqVO) {
132 String token = authService.socialQuickLogin(reqVO, getClientIP(), getUserAgent()); 149 String token = authService.socialQuickLogin(reqVO, getClientIP(), getUserAgent());
133 - // 返回结果  
134 return success(AuthLoginRespVO.builder().token(token).build()); 150 return success(AuthLoginRespVO.builder().token(token).build());
135 } 151 }
136 152
@@ -139,7 +155,6 @@ public class AuthController { @@ -139,7 +155,6 @@ public class AuthController {
139 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 155 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
140 public CommonResult<AuthLoginRespVO> socialBindLogin(@RequestBody @Valid AuthSocialBindLoginReqVO reqVO) { 156 public CommonResult<AuthLoginRespVO> socialBindLogin(@RequestBody @Valid AuthSocialBindLoginReqVO reqVO) {
141 String token = authService.socialBindLogin(reqVO, getClientIP(), getUserAgent()); 157 String token = authService.socialBindLogin(reqVO, getClientIP(), getUserAgent());
142 - // 返回结果  
143 return success(AuthLoginRespVO.builder().token(token).build()); 158 return success(AuthLoginRespVO.builder().token(token).build());
144 } 159 }
145 160
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/auth/OAuth2AccessTokenDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.dal.dataobject.auth;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.TableName;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.experimental.Accessors;
  9 +
  10 +import java.util.Date;
  11 +
  12 +/**
  13 + * OAuth2 访问令牌
  14 + *
  15 + */
  16 +@TableName("system_oauth2_access_token")
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@Accessors(chain = true)
  20 +public class OAuth2AccessTokenDO extends BaseDO {
  21 +
  22 + /**
  23 + * 编号,数据库字典
  24 + */
  25 + private Long id;
  26 + /**
  27 + * 访问令牌
  28 + */
  29 + private String accessToken;
  30 + /**
  31 + * 用户编号
  32 + */
  33 + private Long userId;
  34 + /**
  35 + * 用户类型
  36 + *
  37 + * 枚举 {@link UserTypeEnum}
  38 + */
  39 + private Integer userType;
  40 + /**
  41 + * 刷新令牌
  42 + *
  43 + * 关联 {@link OAuth2RefreshTokenDO#getRefreshToken()}
  44 + */
  45 + private String refreshToken;
  46 + /**
  47 + * 过期时间
  48 + */
  49 + private Date expiresTime;
  50 + /**
  51 + * 创建 IP
  52 + */
  53 + private String createIp;
  54 +
  55 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/auth/OAuth2RefreshTokenDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.dal.dataobject.auth;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.TableName;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.experimental.Accessors;
  9 +
  10 +import java.util.Date;
  11 +
  12 +/**
  13 + * OAuth2 刷新令牌
  14 + *
  15 + */
  16 +@TableName("system_oauth2_refresh_token")
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@Accessors(chain = true)
  20 +public class OAuth2RefreshTokenDO extends BaseDO {
  21 +
  22 + /**
  23 + * 编号,数据库字典
  24 + */
  25 + private Long id;
  26 + /**
  27 + * 刷新令牌
  28 + */
  29 + private String refreshToken;
  30 + /**
  31 + * 用户编号
  32 + */
  33 + private Integer userId;
  34 + /**
  35 + * 用户类型
  36 + *
  37 + * 枚举 {@link UserTypeEnum}
  38 + */
  39 + private Integer userType;
  40 + /**
  41 + * 过期时间
  42 + */
  43 + private Date expiresTime;
  44 + /**
  45 + * 创建 IP
  46 + */
  47 + private String createIp;
  48 +
  49 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java
@@ -20,6 +20,7 @@ public class SecurityConfiguration { @@ -20,6 +20,7 @@ public class SecurityConfiguration {
20 public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { 20 public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
21 // 登录的接口 21 // 登录的接口
22 registry.antMatchers(buildAdminApi("/system/auth/login")).permitAll(); 22 registry.antMatchers(buildAdminApi("/system/auth/login")).permitAll();
  23 + registry.antMatchers(buildAdminApi("/system/auth/logout")).permitAll();
23 // 社交登陆的接口 24 // 社交登陆的接口
24 registry.antMatchers(buildAdminApi("/system/auth/social-auth-redirect")).permitAll(); 25 registry.antMatchers(buildAdminApi("/system/auth/social-auth-redirect")).permitAll();
25 registry.antMatchers(buildAdminApi("/system/auth/social-quick-login")).permitAll(); 26 registry.antMatchers(buildAdminApi("/system/auth/social-quick-login")).permitAll();
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2Service.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.service.auth;
  2 +
  3 +/**
  4 + * OAuth2.0 Service 接口
  5 + *
  6 + * @author 芋道源码
  7 + */
  8 +public interface OAuth2Service {
  9 +
  10 +// OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String createIp);
  11 +//
  12 +// OAuth2AccessTokenRespDTO checkAccessToken(String accessToken);
  13 +//
  14 +// OAuth2AccessTokenRespDTO refreshAccessToken(OAuth2RefreshAccessTokenReqDTO refreshAccessTokenDTO);
  15 +//
  16 +// void removeToken(OAuth2RemoveTokenByUserReqDTO removeTokenDTO);
  17 +
  18 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.service.auth;
  2 +
  3 +import org.springframework.stereotype.Service;
  4 +
  5 +/**
  6 + * OAuth2.0 Service 实现类
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +@Service
  11 +public class OAuth2ServiceImpl implements OAuth2Service {
  12 +
  13 +// @Autowired
  14 +// private SystemBizProperties systemBizProperties;
  15 +//
  16 +// @Autowired
  17 +// private OAuth2AccessTokenMapper oauth2AccessTokenMapper;
  18 +// @Autowired
  19 +// private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper;
  20 +//
  21 +// @Autowired
  22 +// private OAuth2AccessTokenRedisDAO oauth2AccessTokenRedisDAO;
  23 +//
  24 +// @Override
  25 +// @Transactional
  26 +// public OAuth2AccessTokenRespDTO createAccessToken(OAuth2CreateAccessTokenReqDTO createAccessTokenDTO) {
  27 +// // 创建刷新令牌 + 访问令牌
  28 +// OAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(createAccessTokenDTO.getUserId(),
  29 +// createAccessTokenDTO.getUserType(), createAccessTokenDTO.getCreateIp());
  30 +// OAuth2AccessTokenDO accessTokenDO = createOAuth2AccessToken(refreshTokenDO, createAccessTokenDTO.getCreateIp());
  31 +// // 返回访问令牌
  32 +// return OAuth2Convert.INSTANCE.convert(accessTokenDO);
  33 +// }
  34 +//
  35 +// @Override
  36 +// @Transactional
  37 +// public OAuth2AccessTokenRespDTO checkAccessToken(String accessToken) {
  38 +// OAuth2AccessTokenDO accessTokenDO = this.getOAuth2AccessToken(accessToken);
  39 +// if (accessTokenDO == null) { // 不存在
  40 +// throw ServiceExceptionUtil.exception(OAUTH2_ACCESS_TOKEN_NOT_FOUND);
  41 +// }
  42 +// if (accessTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
  43 +// throw ServiceExceptionUtil.exception(OAUTH2_ACCESS_TOKEN_TOKEN_EXPIRED);
  44 +// }
  45 +// // 返回访问令牌
  46 +// return OAuth2Convert.INSTANCE.convert(accessTokenDO);
  47 +// }
  48 +//
  49 +// @Override
  50 +// @Transactional
  51 +// public OAuth2AccessTokenRespDTO refreshAccessToken(OAuth2RefreshAccessTokenReqDTO refreshAccessTokenDTO) {
  52 +// OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectById(refreshAccessTokenDTO.getRefreshToken());
  53 +// // 校验刷新令牌是否合法
  54 +// if (refreshTokenDO == null) { // 不存在
  55 +// throw ServiceExceptionUtil.exception(OAUTH2_REFRESH_TOKEN_NOT_FOUND);
  56 +// }
  57 +// if (refreshTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
  58 +// throw ServiceExceptionUtil.exception(OAUTH_REFRESH_TOKEN_EXPIRED);
  59 +// }
  60 +//
  61 +// // 标记 refreshToken 对应的 accessToken 都不合法
  62 +// // 这块的实现,参考了 Spring Security OAuth2 的代码
  63 +// List<OAuth2AccessTokenDO> accessTokenDOs = oauth2AccessTokenMapper.selectListByRefreshToken(refreshAccessTokenDTO.getRefreshToken());
  64 +// accessTokenDOs.forEach(accessTokenDO -> deleteOAuth2AccessToken(accessTokenDO.getId()));
  65 +//
  66 +// // 创建访问令牌
  67 +// OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(refreshTokenDO, refreshAccessTokenDTO.getCreateIp());
  68 +// // 返回访问令牌
  69 +// return OAuth2Convert.INSTANCE.convert(oauth2AccessTokenDO);
  70 +// }
  71 +//
  72 +// @Override
  73 +// @Transactional
  74 +// public void removeToken(OAuth2RemoveTokenByUserReqDTO removeTokenDTO) {
  75 +// // 删除 Access Token
  76 +// OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByUserIdAndUserType(
  77 +// removeTokenDTO.getUserId(), removeTokenDTO.getUserType());
  78 +// if (accessTokenDO != null) {
  79 +// this.deleteOAuth2AccessToken(accessTokenDO.getId());
  80 +// }
  81 +//
  82 +// // 删除 Refresh Token
  83 +// oauth2RefreshTokenMapper.deleteByUserIdAndUserType(removeTokenDTO.getUserId(), removeTokenDTO.getUserType());
  84 +// }
  85 +//
  86 +// private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2RefreshTokenDO refreshTokenDO, String createIp) {
  87 +// OAuth2AccessTokenDO accessToken = new OAuth2AccessTokenDO()
  88 +// .setId(generateAccessToken())
  89 +// .setUserId(refreshTokenDO.getUserId()).setUserType(refreshTokenDO.getUserType())
  90 +// .setRefreshToken(refreshTokenDO.getId())
  91 +// .setExpiresTime(new Date(System.currentTimeMillis() + systemBizProperties.getAccessTokenExpireTimeMillis()))
  92 +// .setCreateIp(createIp);
  93 +// oauth2AccessTokenMapper.insert(accessToken);
  94 +// return accessToken;
  95 +// }
  96 +//
  97 +// private OAuth2RefreshTokenDO createOAuth2RefreshToken(Integer userId, Integer userType, String createIp) {
  98 +// OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO()
  99 +// .setId(generateRefreshToken())
  100 +// .setUserId(userId).setUserType(userType)
  101 +// .setExpiresTime(new Date(System.currentTimeMillis() + systemBizProperties.getRefreshTokenExpireTimeMillis()))
  102 +// .setCreateIp(createIp);
  103 +// oauth2RefreshTokenMapper.insert(refreshToken);
  104 +// return refreshToken;
  105 +// }
  106 +//
  107 +// private OAuth2AccessTokenDO getOAuth2AccessToken(String accessToken) {
  108 +// // 优先从 Redis 中获取
  109 +// OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenRedisDAO.get(accessToken);
  110 +// if (accessTokenDO != null) {
  111 +// return accessTokenDO;
  112 +// }
  113 +//
  114 +// // 获取不到,从 MySQL 中获取
  115 +// accessTokenDO = oauth2AccessTokenMapper.selectById(accessToken);
  116 +// // 如果在 MySQL 存在,则往 Redis 中写入
  117 +// if (accessTokenDO != null) {
  118 +// oauth2AccessTokenRedisDAO.set(accessTokenDO);
  119 +// }
  120 +// return accessTokenDO;
  121 +// }
  122 +//
  123 +// /**
  124 +// * 删除 accessToken 的 MySQL 与 Redis 的数据
  125 +// *
  126 +// * @param accessToken 访问令牌
  127 +// */
  128 +// private void deleteOAuth2AccessToken(String accessToken) {
  129 +// // 删除 MySQL
  130 +// oauth2AccessTokenMapper.deleteById(accessToken);
  131 +// // 删除 Redis
  132 +// oauth2AccessTokenRedisDAO.delete(accessToken);
  133 +// }
  134 +//
  135 +// private static String generateAccessToken() {
  136 +// return StringUtils.uuid(true);
  137 +// }
  138 +//
  139 +// private static String generateRefreshToken() {
  140 +// return StringUtils.uuid(true);
  141 +// }
  142 +
  143 +}
yudao-ui-admin/src/api/login.js
@@ -26,7 +26,7 @@ export function getInfo() { @@ -26,7 +26,7 @@ export function getInfo() {
26 // 退出方法 26 // 退出方法
27 export function logout() { 27 export function logout() {
28 return request({ 28 return request({
29 - url: '/system/logout', 29 + url: '/system/auth/logout',
30 method: 'post' 30 method: 'post'
31 }) 31 })
32 } 32 }