+ * redis配置 + *
+ * + * @package: com.xkcoding.rbac.security.config + * @description: redis配置 + * @author: yangkai.shen + * @date: Created in 2018-12-11 15:16 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Configuration +@AutoConfigureAfter(RedisAutoConfiguration.class) +@EnableCaching +public class RedisConfig { + + /** + * 默认情况下的模板只能支持RedisTemplate@@ -23,18 +22,9 @@ import org.springframework.security.web.authentication.logout.LogoutSuccessHandl @Configuration public class SecurityHandlerConfig { - /** - * 退出成功处理器 - * - * @return 退出成功处理器 - */ - @Bean - public LogoutSuccessHandler logoutSuccessHandler() { - return (request, response, authentication) -> ResponseUtil.renderJson(response, Status.LOGOUT, null); - } - @Bean public AccessDeniedHandler accessDeniedHandler() { return (request, response, accessDeniedException) -> ResponseUtil.renderJson(response, Status.ACCESS_DENIED, null); } + } diff --git a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/controller/AuthController.java b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/controller/AuthController.java index db3605e..6e5f578 100644 --- a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/controller/AuthController.java +++ b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/controller/AuthController.java @@ -1,11 +1,14 @@ package com.xkcoding.rbac.security.controller; import com.xkcoding.rbac.security.common.ApiResponse; +import com.xkcoding.rbac.security.common.Status; +import com.xkcoding.rbac.security.exception.SecurityException; import com.xkcoding.rbac.security.payload.LoginRequest; import com.xkcoding.rbac.security.util.JwtUtil; import com.xkcoding.rbac.security.vo.JwtResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -15,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; /** @@ -51,7 +55,18 @@ public class AuthController { SecurityContextHolder.getContext() .setAuthentication(authentication); - String jwt = jwtUtil.createJWT(authentication); + String jwt = jwtUtil.createJWT(authentication,loginRequest.getRememberMe()); return ApiResponse.ofSuccess(new JwtResponse(jwt)); } + + @PostMapping("/logout") + public ApiResponse logout(HttpServletRequest request) { + try { + // 设置JWT过期 + jwtUtil.invalidateJWT(request); + } catch (SecurityException e) { + throw new SecurityException(Status.UNAUTHORIZED); + } + return ApiResponse.ofStatus(Status.LOGOUT); + } } diff --git a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/exception/SecurityException.java b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/exception/SecurityException.java index 884d643..4b02465 100644 --- a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/exception/SecurityException.java +++ b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/exception/SecurityException.java @@ -2,7 +2,8 @@ package com.xkcoding.rbac.security.exception; import com.xkcoding.rbac.security.common.BaseException; import com.xkcoding.rbac.security.common.Status; -import lombok.Getter; +import lombok.Data; +import lombok.EqualsAndHashCode; /** *
@@ -17,7 +18,8 @@ import lombok.Getter; * @version: V1.0 * @modified: yangkai.shen */ -@Getter +@EqualsAndHashCode(callSuper = true) +@Data public class SecurityException extends BaseException { public SecurityException(Status status) { super(status); diff --git a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/exception/handler/GlobalExceptionHandler.java b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/exception/handler/GlobalExceptionHandler.java index e38b98d..909638c 100644 --- a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/exception/handler/GlobalExceptionHandler.java +++ b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/exception/handler/GlobalExceptionHandler.java @@ -1,6 +1,7 @@ package com.xkcoding.rbac.security.exception.handler; import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONUtil; import com.xkcoding.rbac.security.common.ApiResponse; import com.xkcoding.rbac.security.common.BaseException; import com.xkcoding.rbac.security.common.Status; @@ -8,6 +9,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; +import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -40,6 +42,9 @@ public class GlobalExceptionHandler { if (e instanceof NoHandlerFoundException) { log.error("【全局异常拦截】NoHandlerFoundException: 请求方法 {}, 请求路径 {}", ((NoHandlerFoundException) e).getRequestURL(), ((NoHandlerFoundException) e).getHttpMethod()); return ApiResponse.ofStatus(Status.REQUEST_NOT_FOUND); + } else if (e instanceof HttpRequestMethodNotSupportedException) { + log.error("【全局异常拦截】HttpRequestMethodNotSupportedException: 当前请求方式 {}, 支持请求方式 {}", ((HttpRequestMethodNotSupportedException) e).getMethod(), JSONUtil.toJsonStr(((HttpRequestMethodNotSupportedException) e).getSupportedHttpMethods())); + return ApiResponse.ofStatus(Status.HTTP_BAD_METHOD); } else if (e instanceof MethodArgumentNotValidException) { log.error("【全局异常拦截】MethodArgumentNotValidException", e); return ApiResponse.of(Status.BAD_REQUEST.getCode(), ((MethodArgumentNotValidException) e).getBindingResult() diff --git a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/payload/LoginRequest.java b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/payload/LoginRequest.java index eb473d0..3c9a0c5 100644 --- a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/payload/LoginRequest.java +++ b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/payload/LoginRequest.java @@ -23,13 +23,18 @@ public class LoginRequest { /** * 用户名或邮箱或手机号 */ - @NotBlank + @NotBlank(message = "用户名不能为空") private String usernameOrEmailOrPhone; /** * 密码 */ - @NotBlank + @NotBlank(message = "密码不能为空") private String password; + /** + * 记住我 + */ + private Boolean rememberMe = false; + } diff --git a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/util/JwtUtil.java b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/util/JwtUtil.java index c66c398..305279c 100644 --- a/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/util/JwtUtil.java +++ b/spring-boot-demo-rbac-security/src/main/java/com/xkcoding/rbac/security/util/JwtUtil.java @@ -1,6 +1,8 @@ package com.xkcoding.rbac.security.util; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.xkcoding.rbac.security.common.Consts; import com.xkcoding.rbac.security.common.Status; import com.xkcoding.rbac.security.config.JwtConfig; import com.xkcoding.rbac.security.exception.SecurityException; @@ -10,12 +12,16 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; +import javax.servlet.http.HttpServletRequest; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; /** *
@@ -34,23 +40,23 @@ import java.util.List;
@Configuration
@Slf4j
public class JwtUtil {
- private final JwtConfig jwtConfig;
+ @Autowired
+ private JwtConfig jwtConfig;
@Autowired
- public JwtUtil(JwtConfig jwtConfig) {
- this.jwtConfig = jwtConfig;
- }
+ private StringRedisTemplate stringRedisTemplate;
/**
* 创建JWT
*
+ * @param rememberMe 记住我
* @param id 用户id
* @param subject 用户名
* @param roles 用户角色
* @param authorities 用户权限
* @return JWT
*/
- public String createJWT(Long id, String subject, List