Secondary Authentication for Sensitive Operations——Detailed Sa-Token Secondary Authentication

1. Demand analysis

Under certain sensitive operations, we need to perform secondary authentication on the logged-in session.

For example, the warehouse deletion operation of the code hosting platform, although we have already logged in the account, when we click the [Delete] button, we still need to enter the password again. This is mainly for two points:

  1. Make sure that the operator is the current account owner.
  2. Added operation steps to prevent accidental deletion of important data.

This is what we are going to talk about in this article—two-level authentication, that is, to re-authenticate on the basis of the logged-in session to improve the security of the session.

Sa-Token is a lightweight java authority authentication framework, which mainly solves a series of authority-related issues such as login authentication, authority authentication, single sign-on, OAuth2, and microservice gateway authentication. Gitee open source address: https://gitee.com/dromara/sa-token

This article will introduce how to use Sa-Token to complete the secondary authentication operation under the SpringBoot architecture.

First introduce the Sa-Token dependency in the project:

<!-- Sa-Token 权限认证 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.34.0</version>
</dependency>

Note: If you are using SpringBoot 3.x, just sa-token-spring-boot-starterchange to sa-token-spring-boot3-starter.

2. Specific APIs

It is very simple to do two-level authentication in Sa-Token, just use the following API:

// 在当前会话 开启二级认证,时间为120秒
StpUtil.openSafe(120); 

// 获取:当前会话是否处于二级认证时间内
StpUtil.isSafe(); 

// 检查当前会话是否已通过二级认证,如未通过则抛出异常
StpUtil.checkSafe(); 

// 获取当前会话的二级认证剩余有效时间 (单位: 秒, 返回-2代表尚未通过二级认证)
StpUtil.getSafeTime(); 

// 在当前会话 结束二级认证
StpUtil.closeSafe(); 

3. A small example

A complete secondary authentication business process should be roughly as follows:

package com.pj.cases.up;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;

/**
 * Sa-Token 二级认证示例 
 * 
 * @author kong
 * @since 2022-10-16 
 */
@RestController
@RequestMapping("/safe/")
public class SafeAuthController {
	
	// 删除仓库    ---- http://localhost:8081/safe/deleteProject
	@RequestMapping("deleteProject")
	public SaResult deleteProject(String projectId) {
	    // 第1步,先检查当前会话是否已完成二级认证 
		// 		这个地方既可以通过 StpUtil.isSafe() 手动判断,
		// 		也可以通过 StpUtil.checkSafe() 或者 @SaCheckSafe 来校验(校验不通过时将抛出 NotSafeException 异常)
	    if(!StpUtil.isSafe()) {
	        return SaResult.error("仓库删除失败,请完成二级认证后再次访问接口");
	    }
	
	    // 第2步,如果已完成二级认证,则开始执行业务逻辑
	    // ... 
	
	    // 第3步,返回结果 
	    return SaResult.ok("仓库删除成功"); 
	}
	
	// 提供密码进行二级认证    ---- http://localhost:8081/safe/openSafe?password=123456
	@RequestMapping("openSafe")
	public SaResult openSafe(String password) {
	    // 比对密码(此处只是举例,真实项目时可拿其它参数进行校验)
	    if("123456".equals(password)) {
	
	        // 比对成功,为当前会话打开二级认证,有效期为120秒,意为在120秒内再调用 deleteProject 接口都无需提供密码 
	        StpUtil.openSafe(120);
	        return SaResult.ok("二级认证成功");
	    }
	
	    // 如果密码校验失败,则二级认证也会失败
	    return SaResult.error("二级认证失败"); 
	}

	// 手动关闭二级认证    ---- http://localhost:8081/safe/closeSafe
	@RequestMapping("closeSafe")
	public SaResult closeSafe() {
		StpUtil.closeSafe();
	    return SaResult.ok();
	}

}

Global exception interceptor, uniformly returned to the front-end format, refer to:

@RestControllerAdvice
public class GlobalExceptionHandler {
    // 全局异常拦截 
    @ExceptionHandler
    public SaResult handlerException(Exception e) {
        e.printStackTrace(); 
        return SaResult.error(e.getMessage());
    }
}

Premise: We must be in the login state during the second-level authentication (refer to the previous login authentication chapter code), after completing the login, call the interface to perform the second-level authentication verification:

  1. The front end calls the deleteProject interface to try to delete the warehouse. ----http://localhost:8081/safe/deleteProject
  2. The backend verification session has not yet completed the second-level authentication, and returns: Failed to delete the warehouse, please access the interface again after completing the second-level authentication.
  3. The front end prompts the information to the user, the user enters the password, and calls the openSafe interface. ----http://localhost:8081/safe/openSafe?password=123456
  4. The backend compares the password entered by the user to complete the secondary authentication, and the validity period is: 120 seconds.
  5. The front end calls the deleteProject interface again within 120 seconds to try to delete the warehouse. ----http://localhost:8081/safe/deleteProject
  6. The backend verifies that the session has completed the second-level authentication, and returns: the warehouse is deleted successfully.

4. Specify the business logo for secondary certification

If multiple business lines of the project require sensitive operation verification, StpUtil.openSafe()fine-grained authentication operations cannot be provided. At this time, we can specify a business identifier to distinguish different business lines:

// 在当前会话 开启二级认证,业务标识为client,时间为600秒
StpUtil.openSafe("client", 600); 

// 获取:当前会话是否已完成指定业务的二级认证 
StpUtil.isSafe("client"); 

// 校验:当前会话是否已完成指定业务的二级认证 ,如未认证则抛出异常
StpUtil.checkSafe("client"); 

// 获取当前会话指定业务二级认证剩余有效时间 (单位: 秒, 返回-2代表尚未通过二级认证)
StpUtil.getSafeTime("client"); 

// 在当前会话 结束指定业务标识的二级认证
StpUtil.closeSafe("client"); 

The business ID can be filled with any string, and the authentication between different business IDs does not affect each other, for example:

// 打开了业务标识为 client 的二级认证 
StpUtil.openSafe("client"); 

// 判断是否处于 shop 的二级认证,会返回 false 
StpUtil.isSafe("shop");  // 返回 false 

// 也不会通过校验,会抛出异常 
StpUtil.checkSafe("shop"); 

Code example:

package com.pj.cases.up;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;

/**
 * Sa-Token 二级认证示例 
 * 
 * @author kong
 * @since 2022-10-16 
 */
@RestController
@RequestMapping("/safe/")
public class SafeAuthController {

	// ------------------ 指定业务类型进行二级认证 

	// 获取应用秘钥    ---- http://localhost:8081/safe/getClientSecret
	@RequestMapping("getClientSecret")
	public SaResult getClientSecret() {
	    // 第1步,先检查当前会话是否已完成 client业务 的二级认证 
		StpUtil.checkSafe("client");
	
	    // 第2步,如果已完成二级认证,则返回数据 
	    return SaResult.data("aaaa-bbbb-cccc-dddd-eeee");
	}
	
	// 提供手势密码进行二级认证    ---- http://localhost:8081/safe/openClientSafe?gesture=3578
	@RequestMapping("openClientSafe")
	public SaResult openClientSafe(String gesture) {
	    // 比对手势密码(此处只是举例,真实项目时可拿其它参数进行校验)
	    if("3578".equals(gesture)) {
	
	        // 比对成功,为当前会话打开二级认证:
	    	// 业务类型为:client 
	    	// 有效期为600秒==10分钟,意为在10分钟内,调用 getClientSecret 时都无需再提供手势密码 
	        StpUtil.openSafe("client", 600);
	        return SaResult.ok("二级认证成功");
	    }
	
	    // 如果密码校验失败,则二级认证也会失败
	    return SaResult.error("二级认证失败"); 
	}

	// 查询当前会话是否已完成指定的二级认证    ---- http://localhost:8081/safe/isClientSafe
	@RequestMapping("isClientSafe")
	public SaResult isClientSafe() {
	    return SaResult.ok("当前是否已完成 client 二级认证:" + StpUtil.isSafe("client")); 
	}

}

5. Use annotations for secondary authentication

Use annotations on a method @SaCheckSafeto perform a secondary authentication check before the code enters this method

// 二级认证:必须二级认证之后才能进入该方法 
@SaCheckSafe      
@RequestMapping("add")
public String add() {
    return "用户增加";
}

// 指定业务类型,进行二级认证校验
@SaCheckSafe("art")
@RequestMapping("add2")
public String add2() {
    return "文章增加";
}

The method marked @SaCheckSafemust be accessed successfully after the second-level authentication, and its effect is StpUtil.checkSafe()equivalent to the code.


References

RustDesk 1.2: Using Flutter to rewrite the desktop version, supporting Wayland's alleged GPT-4 model architecture leak: Contains 1.8 trillion parameters, using a mixed expert model (MoE) Musk announced the establishment of xAI company deepin V23 successfully adapted WSL CentOS project claims " Open to all" Rust 1.71.0 Stable Release React Is it having an Angular.js moment? Microsoft launches a new default font, Aptos, to replace CalibriMicrosoft : Increase efforts to use Rust IntelliJ IDEA 2023.1.4 release on Windows 11
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/3503445/blog/10086446