SpringBoot utilise Sa-Token pour réaliser l'interdiction de compte, l'interdiction de classification et l'interdiction d'échelle

1. Analyse de la demande

Dans les chapitres précédents, nous avons appris les fonctions de mise hors ligne des personnes et de déconnexion forcée, qui sont utilisées pour effacer les comptes illégaux. Dans certains scénarios, nous devons également interdire leurs comptes pour les empêcher de se reconnecter.

Sa-Token est un framework d'authentification d'autorité Java léger, qui résout principalement une série de problèmes liés à l'autorité tels que l'authentification de connexion, l'authentification d'autorité, l'authentification unique, OAuth2 et l'authentification de passerelle de microservice. Adresse open source de Gitee : gitee.com/dromara/sa-…

Il existe trois types d'opérations d'interdiction fournies par Sa-Token :

  • Interdiction de compte : interdire la capacité de connexion d'un compte, rendant impossible la connexion.
  • Interdiction classifiée : interdire une partie de l'autorité d'exploitation commerciale d'un compte sans affecter les fonctions de base telles que la connexion globale du compte.
  • Interdiction à plusieurs niveaux : selon différents degrés de violation, différentes interdictions sont prononcées.

Cet article présentera comment effectuer les trois opérations d'interdiction ci-dessus dans Sa-Token.

Commencez par introduire la dépendance Sa-Token dans le projet :

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

Remarque : Si vous utilisez SpringBoot 3.x, sa-token-spring-boot-starterremplacez-le simplement par sa-token-spring-boot3-starter.

2. Bannissement de compte

Bannissez le compte spécifié :

// 封禁指定账号 
StpUtil.disable(10001, 86400); 

Signification du paramètre :

  • Paramètre 1 : L'identifiant du compte à bannir.
  • Paramètre 2 : Temps d'interdiction, unité : seconde, c'est 86400 secondes = 1 jour (lorsque cette valeur est -1, cela signifie une interdiction permanente).

Points à noter : pour un compte actuellement connecté, le bannir ne le mettra pas immédiatement hors ligne. Si nous avons besoin qu'il se déconnecte immédiatement, nous pouvons d'abord utiliser la stratégie consistant à expulser et à bannir, par exemple :

// 先踢下线
StpUtil.kickout(10001); 
// 再封禁账号
StpUtil.disable(10001, 86400); 

Lors de notre prochaine connexion, vérifions si le compte a été banni :

// 校验指定账号是否已被封禁,如果被封禁则抛出异常 `DisableServiceException`
StpUtil.checkDisable(10001); 

// 通过校验后,再进行登录:
StpUtil.login(10001); 

L'ancienne version StpUtil.login()vérifiera automatiquement si le compte est banni ou non. Après la v1.31.0, les deux actions de vérification de l'interdiction et de connexion sont séparées en deux méthodes, et la vérification automatique n'est plus effectuée. Veuillez prêter attention à la logique changements.

Toutes les méthodes de ce module :

// 封禁指定账号 
StpUtil.disable(10001, 86400); 

// 获取指定账号是否已被封禁 (true=已被封禁, false=未被封禁) 
StpUtil.isDisable(10001); 

// 校验指定账号是否已被封禁,如果被封禁则抛出异常 `DisableServiceException`
StpUtil.checkDisable(10001); 

// 获取指定账号剩余封禁时间,单位:秒,如果该账号未被封禁,则返回-2 
StpUtil.getDisableTime(10001); 

// 解除封禁
StpUtil.untieDisable(10001); 

3. Interdiction de catégorie

Parfois, nous n'avons pas besoin d'interdire l'intégralité du compte, mais seulement de lui interdire l'accès à certains services.

En supposant que nous développions un système de commerce électronique, nous avons défini trois types d'interdictions pour punir les comptes illégaux :

  • 1、封禁评价能力:账号A 因为多次虚假好评,被限制订单评价功能。
  • 2、封禁下单能力:账号B 因为多次薅羊毛,被限制下单功能。
  • 3、封禁开店能力:账号C 因为店铺销售假货,被限制开店功能。

相比于封禁账号的一刀切处罚,这里的关键点在于:每一项能力封禁的同时,都不会对其它能力造成影响。

也就是说我们需要一种只对部分服务进行限制的能力,对应到代码层面,就是只禁止部分接口的调用。

// 封禁指定用户评论能力,期限为 1天
StpUtil.disable(10001, "comment", 86400);

参数释义:

  • 参数1:要封禁的账号id。
  • 参数2:针对这个账号,要封禁的服务标识(可以是任意的自定义字符串)。
  • 参数3:要封禁的时间,单位:秒,此为 86400秒 = 1天(此值为 -1 时,代表永久封禁)。

分类封禁模块所有可用API:

/*
 * 以下示例中:"comment"=评论服务标识、"place-order"=下单服务标识、"open-shop"=开店服务标识
 */

// 封禁指定用户评论能力,期限为 1天
StpUtil.disable(10001, "comment", 86400);

// 在评论接口,校验一下,会抛出异常:`DisableServiceException`,使用 e.getService() 可获取业务标识 `comment` 
StpUtil.checkDisable(10001, "comment");

// 在下单时,我们校验一下 下单能力,并不会抛出异常,因为我们没有限制其下单功能
StpUtil.checkDisable(10001, "place-order");

// 现在我们再将其下单能力封禁一下,期限为 7天 
StpUtil.disable(10001, "place-order", 86400 * 7);

// 然后在下单接口,我们添加上校验代码,此时用户便会因为下单能力被封禁而无法下单(代码抛出异常)
StpUtil.checkDisable(10001, "place-order");

// 但是此时,用户如果调用开店功能的话,还是可以通过,因为我们没有限制其开店能力 (除非我们再调用了封禁开店的代码)
StpUtil.checkDisable(10001, "open-shop");

通过以上示例,你应该大致可以理解 业务封禁 -> 业务校验 的处理步骤。

有关分类封禁的所有方法:

// 封禁:指定账号的指定服务 
StpUtil.disable(10001, "<业务标识>", 86400); 

// 判断:指定账号的指定服务 是否已被封禁 (true=已被封禁, false=未被封禁) 
StpUtil.isDisable(10001, "<业务标识>"); 

// 校验:指定账号的指定服务 是否已被封禁,如果被封禁则抛出异常 `DisableServiceException`
StpUtil.checkDisable(10001, "<业务标识>"); 

// 获取:指定账号的指定服务 剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
StpUtil.getDisableTime(10001, "<业务标识>"); 

// 解封:指定账号的指定服务
StpUtil.untieDisable(10001, "<业务标识>"); 

四、阶梯封禁

对于多次违规的用户,我们常常采取阶梯处罚的策略,这种 “阶梯” 一般有两种形式:

  • 处罚时间阶梯:首次违规封禁 1 天,第二次封禁 7 天,第三次封禁 30 天,依次顺延……
  • 处罚力度阶梯:首次违规消息提醒、第二次禁言禁评论、第三次禁止账号登录,等等……

基于处罚时间的阶梯,我们只需在封禁时 StpUtil.disable(10001, 86400) 传入不同的封禁时间即可,下面我们着重探讨一下基于处罚力度的阶梯形式。

假设我们在开发一个论坛系统,对于违规账号的处罚,我们设定三种力度:

  • 1、轻度违规:封禁其发帖、评论能力,但允许其点赞、关注等操作。
  • 2、中度违规:封禁其发帖、评论、点赞、关注等一切与别人互动的能力,但允许其浏览帖子、浏览评论。
  • 3、重度违规:封禁其登录功能,限制一切能力。

解决这种需求的关键在于,我们需要把不同处罚力度,量化成不同的处罚等级,比如上述的 轻度中度重度 3 个力度, 我们将其量化为一级封禁二级封禁三级封禁 3个等级,数字越大代表封禁力度越高。

Ensuite, nous pouvons utiliser l'API ladder-banned pour l'authentification :

// 阶梯封禁,参数:封禁账号、封禁级别、封禁时间 
StpUtil.disableLevel(10001, 3, 10000);

// 获取:指定账号封禁的级别 (如果此账号未被封禁则返回 -2)
StpUtil.getDisableLevel(10001);

// 判断:指定账号是否已被封禁到指定级别,返回 true 或 false
StpUtil.isDisableLevel(10001, 3);

// 校验:指定账号是否已被封禁到指定级别,如果已达到此级别(例如已被3级封禁,这里校验是否达到2级),则抛出异常 `DisableServiceException`
StpUtil.checkDisableLevel(10001, 2);

Remarque : DisableServiceExceptionl'exception signifie que le compte actuel n'a pas passé la vérification de l'interdiction, vous pouvez :

  • Obtenez le niveau auquel e.getLevel()ce compte est effectivement interdit par .
  • Obtenez e.getLimitLevel()le niveau que ce compte requiert pour être inférieur à celui lors de la vérification par . À ce Level >= LimitLevelmoment- , le framework lèvera une exception.

Si l'entreprise est suffisamment complexe, nous pouvons également utiliser une combinaison d'interdictions classifiées et d'interdictions d'échelle :

// 分类阶梯封禁,参数:封禁账号、封禁服务、封禁级别、封禁时间 
StpUtil.disableLevel(10001, "comment", 3, 10000);

// 获取:指定账号的指定服务 封禁的级别 (如果此账号未被封禁则返回 -2)
StpUtil.getDisableLevel(10001, "comment");

// 判断:指定账号的指定服务 是否已被封禁到指定级别,返回 true 或 false
StpUtil.isDisableLevel(10001, "comment", 3);

// 校验:指定账号的指定服务 是否已被封禁到指定级别(例如 comment服务 已被3级封禁,这里校验是否达到2级),如果已达到此级别,则抛出异常 
StpUtil.checkDisableLevel(10001, "comment", 2);

5. Utilisez des annotations pour compléter la vérification de l'interdiction

Nous devons d'abord enregistrer l'intercepteur global Sa-Token :

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
	// 注册 Sa-Token 拦截器,打开注解式鉴权功能 
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");	
	}
}

Ensuite, nous pouvons utiliser les annotations suivantes pour vérifier si le compte est banni :

// 校验当前账号是否被封禁,如果已被封禁会抛出异常,无法进入方法 
@SaCheckDisable
@PostMapping("send")
public SaResult send() {
	// ... 
	return SaResult.ok(); 
}

// 校验当前账号是否被封禁 comment 服务,如果已被封禁会抛出异常,无法进入方法 
@SaCheckDisable("comment")
@PostMapping("send")
public SaResult send() {
	// ... 
	return SaResult.ok(); 
}

// 校验当前账号是否被封禁 comment、place-order、open-shop 等服务,指定多个值,只要有一个已被封禁,就无法进入方法 
@SaCheckDisable({"comment", "place-order", "open-shop"})
@PostMapping("send")
public SaResult send() {
	// ... 
	return SaResult.ok(); 
}

// 阶梯封禁,校验当前账号封禁等级是否达到5级,如果达到则抛出异常 
@SaCheckDisable(level = 5)
@PostMapping("send")
public SaResult send() {
	// ... 
	return SaResult.ok(); 
}

// 分类封禁 + 阶梯封禁 校验:校验当前账号的 comment 服务,封禁等级是否达到5级,如果达到则抛出异常 
@SaCheckDisable(value = "comment", level = 5)
@PostMapping("send")
public SaResult send() {
	// ... 
	return SaResult.ok(); 
}

Sixièmement, un petit exemple pour approfondir la compréhension

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-17 
 */
@RestController
@RequestMapping("/disable/")
public class DisableController {

	// 会话登录接口  ---- http://localhost:8081/disable/login?userId=10001
	@RequestMapping("login")
	public SaResult login(long userId) {
		// 1、先检查此账号是否已被封禁 
		StpUtil.checkDisable(userId);
		// 2、检查通过后,再登录 
		StpUtil.login(userId);
		return SaResult.ok("账号登录成功");
	}

	// 会话注销接口  ---- http://localhost:8081/disable/logout
	@RequestMapping("logout")
	public SaResult logout() {
		StpUtil.logout();
		return SaResult.ok("账号退出成功");
	}

	// 封禁指定账号  ---- http://localhost:8081/disable/disable?userId=10001
	@RequestMapping("disable")
	public SaResult disable(long userId) {
		/*
		 * 账号封禁:
		 * 	参数1:要封禁的账号id
		 * 	参数2:要封禁的时间,单位:秒,86400秒=1天
		 */
		StpUtil.disable(userId, 86400);
		return SaResult.ok("账号 " + userId + " 封禁成功");
	}

	// 解封指定账号  ---- http://localhost:8081/disable/untieDisable?userId=10001
	@RequestMapping("untieDisable")
	public SaResult untieDisable(long userId) {
		StpUtil.untieDisable(userId);
		return SaResult.ok("账号 " + userId + " 解封成功");
	}

}

Étapes d'essai :

  1. Accédez à l'interface de connexion, vous pouvez vous connecter normalement ----http://localhost:8081/disable/login?userId=10001
  2. Se déconnecter----http://localhost:8081/disable/logout
  3. Désactiver le compte ----http://localhost:8081/disable/disable?userId=10001
  4. Accédez à nouveau à l'interface de connexion et la connexion échoue ----http://localhost:8081/disable/login?userId=10001
  5. Débloquer le compte----http://localhost:8081/disable/untieDisable?userId=10001
  6. Visitez à nouveau l'interface de connexion et la connexion est réussie----http://localhost:8081/disable/login?userId=10001

Les références

Guess you like

Origin juejin.im/post/7256622070216327226