提交 46b3828b 作者: 方治民

feat: 新增二级认证接口及示例

上级 81c4cf7d
/* (C) 2021 YiRing, Inc. */ /* (C) 2021 YiRing, Inc. */
package com.yiring.app.config; package com.yiring.app.config;
import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.*;
import com.yiring.common.core.I18n; import com.yiring.common.core.I18n;
import com.yiring.common.core.Result; import com.yiring.common.core.Result;
import com.yiring.common.core.Status; import com.yiring.common.core.Status;
...@@ -47,7 +47,7 @@ public class GlobalExceptionHandler { ...@@ -47,7 +47,7 @@ public class GlobalExceptionHandler {
* @return 统一的校验失败信息 {@link Status#EXPECTATION_FAILED * @return 统一的校验失败信息 {@link Status#EXPECTATION_FAILED
*/ */
@ExceptionHandler( @ExceptionHandler(
value = { BindException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class } { BindException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class }
) )
public Result<String> bindErrorHandler(Exception e) { public Result<String> bindErrorHandler(Exception e) {
String details = null; String details = null;
...@@ -107,6 +107,30 @@ public class GlobalExceptionHandler { ...@@ -107,6 +107,30 @@ public class GlobalExceptionHandler {
} }
/** /**
* 1. 二级认证失败异常
* 2. 角色条件不满足
* 3. 权限条件不满足
* 4. HTTP Basic 验证不通过
* 5. 用户被禁止访问该服务
* 6. API 被禁用
*
* @return 异常信息反馈 {@link Status#FORBIDDEN
*/
@ExceptionHandler(
{
NotSafeException.class,
NotRoleException.class,
NotPermissionException.class,
NotBasicAuthException.class,
DisableServiceException.class,
ApiDisabledException.class,
}
)
public Result<String> notSafeErrorHandler() {
return Result.no(Status.FORBIDDEN);
}
/**
* 自定义业务异常 * 自定义业务异常
*/ */
@ExceptionHandler(BusinessException.class) @ExceptionHandler(BusinessException.class)
...@@ -125,9 +149,7 @@ public class GlobalExceptionHandler { ...@@ -125,9 +149,7 @@ public class GlobalExceptionHandler {
/** /**
* 取消请求异常(忽略) * 取消请求异常(忽略)
*/ */
@ExceptionHandler( @ExceptionHandler({ ClientAbortException.class, AbortException.class, HttpMessageNotWritableException.class })
value = { ClientAbortException.class, AbortException.class, HttpMessageNotWritableException.class }
)
public void clientAbortExceptionHandler() {} public void clientAbortExceptionHandler() {}
/** /**
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
package com.yiring.app.web.example; package com.yiring.app.web.example;
import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckSafe;
import com.github.xiaoymin.knife4j.annotations.ApiSupport; import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.yiring.app.domain.user.UserExtension; import com.yiring.app.domain.user.UserExtension;
import com.yiring.app.domain.user.UserExtensionRepository; import com.yiring.app.domain.user.UserExtensionRepository;
...@@ -64,7 +65,7 @@ public class ExampleController { ...@@ -64,7 +65,7 @@ public class ExampleController {
@ApiOperation("测试失败") @ApiOperation("测试失败")
@GetMapping("fail") @GetMapping("fail")
public Result<String> fail() { public Result<String> fail() {
throw BusinessException.i18n("Code.100000"); throw BusinessException.i18n("Code.1");
} }
@SaCheckLogin @SaCheckLogin
...@@ -94,6 +95,7 @@ public class ExampleController { ...@@ -94,6 +95,7 @@ public class ExampleController {
FileUtils.download(response, resource.getFile()); FileUtils.download(response, resource.getFile());
} }
@SaCheckSafe
@SaCheckLogin @SaCheckLogin
@ApiOperation("查询用户属性") @ApiOperation("查询用户属性")
@GetMapping("findUserExtensionInfo") @GetMapping("findUserExtensionInfo")
......
...@@ -24,6 +24,7 @@ public class SaTokenConfigure implements WebMvcConfigurer { ...@@ -24,6 +24,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 路由拦截器 // 注册 Sa-Token 路由拦截器
// 可搭配使用注解实现鉴权: https://sa-token.dev33.cn/doc.html#/use/at-check
registry registry
.addInterceptor( .addInterceptor(
new SaInterceptor(handle -> { new SaInterceptor(handle -> {
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.auth.param.auth;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.constraints.NotEmpty;
import lombok.*;
import lombok.experimental.FieldDefaults;
/**
* 安全校验参数
*
* @author ifzm
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel("SafeParam")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class SafeParam implements Serializable {
@Serial
private static final long serialVersionUID = 9106494470582579138L;
@ApiModelProperty(value = "密码", example = "123456", required = true)
@NotEmpty(message = "密码不能为空")
String password;
}
/* (C) 2022 YiRing, Inc. */ /* (C) 2022 YiRing, Inc. */
package com.yiring.auth.web.auth; package com.yiring.auth.web.auth;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.secure.SaSecureUtil; import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
...@@ -9,6 +10,8 @@ import com.yiring.auth.domain.user.User; ...@@ -9,6 +10,8 @@ import com.yiring.auth.domain.user.User;
import com.yiring.auth.domain.user.UserRepository; import com.yiring.auth.domain.user.UserRepository;
import com.yiring.auth.param.auth.LoginParam; import com.yiring.auth.param.auth.LoginParam;
import com.yiring.auth.param.auth.RegisterParam; import com.yiring.auth.param.auth.RegisterParam;
import com.yiring.auth.param.auth.SafeParam;
import com.yiring.auth.util.Auths;
import com.yiring.auth.vo.auth.LoginVo; import com.yiring.auth.vo.auth.LoginVo;
import com.yiring.common.core.Result; import com.yiring.common.core.Result;
import com.yiring.common.exception.BusinessException; import com.yiring.common.exception.BusinessException;
...@@ -16,9 +19,9 @@ import com.yiring.common.util.Commons; ...@@ -16,9 +19,9 @@ import com.yiring.common.util.Commons;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid; import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Example; import org.springframework.data.domain.Example;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
...@@ -42,10 +45,11 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -42,10 +45,11 @@ import org.springframework.web.bind.annotation.RestController;
@Api(tags = "身份认证", description = "Auth") @Api(tags = "身份认证", description = "Auth")
@RestController @RestController
@RequestMapping("/auth/") @RequestMapping("/auth/")
@RequiredArgsConstructor
public class AuthController { public class AuthController {
@Resource final Auths auths;
UserRepository userRepository; final UserRepository userRepository;
@ApiOperation(value = "注册") @ApiOperation(value = "注册")
@PostMapping("register") @PostMapping("register")
...@@ -123,7 +127,7 @@ public class AuthController { ...@@ -123,7 +127,7 @@ public class AuthController {
return Result.ok(vo); return Result.ok(vo);
} }
@ApiOperation(value = "检查登录状态") @ApiOperation(value = "检查登录")
@GetMapping("valid") @GetMapping("valid")
public Result<Boolean> valid() { public Result<Boolean> valid() {
return Result.ok(StpUtil.isLogin()); return Result.ok(StpUtil.isLogin());
...@@ -135,4 +139,25 @@ public class AuthController { ...@@ -135,4 +139,25 @@ public class AuthController {
StpUtil.logout(); StpUtil.logout();
return Result.ok(); return Result.ok();
} }
/**
* 二次安全校验,搭配 @SaCheckSafe 实现对关键数据不可逆操作前的二次确认
* 默认安全时间: 120s
*
* @param param 用户密码
* @return
* @link { https://sa-token.dev33.cn/doc.html#/up/safe-auth }
*/
@SaCheckLogin
@ApiOperation(value = "安全校验")
@GetMapping("safe")
public Result<String> safe(@Valid SafeParam param) {
User user = auths.getLoginUser();
if (SaSecureUtil.sha256(param.getPassword()).equals(user.getPassword())) {
StpUtil.openSafe(120);
return Result.ok();
}
return Result.no();
}
} }
...@@ -35,7 +35,7 @@ public enum Status { ...@@ -35,7 +35,7 @@ public enum Status {
UNAUTHORIZED(401, "Status.UNAUTHORIZED"), UNAUTHORIZED(401, "Status.UNAUTHORIZED"),
/** /**
* Token 错误/失效 * 禁止访问(可能是二级认证失败)
*/ */
FORBIDDEN(403, "Status.FORBIDDEN"), FORBIDDEN(403, "Status.FORBIDDEN"),
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论