查看: 164|回复: 0

[Java学习] Spring Security 强制退出指定用户的方法

发表于 4 天前

应用场景

最近社区总有人发文章带上小广告,严重影响社区氛围,好气!对于这种类型的用户,就该永久拉黑!

社区的安全框架使用了 spring-security 和 spring-session,登录状态 30 天有效,session 信息是存在 redis 中,如何优雅地处理这些不老实的用户呢?

首先,简单划分下用户的权限:

  1. 管理员(ROLE_MANAGER):基本操作 + 管理操作
  2. 普通用户(ROLE_USER):基本操作
  3. 拉黑用户(ROLE_BLACK):不允许登录

然后,拉黑指定用户(ROLE_USER -> ROLE_BLACK),再强制该用户退出即可(删除该用户在 redis 中 session 信息)。

项目相关依赖及配置

Maven 依赖

  1. <!-- 安全 Security -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-security</artifactId>
  5. </dependency>
  6. <!-- Redis -->
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-data-redis</artifactId>
  10. </dependency>
  11. <!-- Spring Session Redis -->
  12. <dependency>
  13. <groupId>org.springframework.session</groupId>
  14. <artifactId>spring-session-data-redis</artifactId>
  15. </dependency>
复制代码

Spring Session 策略配置 application.yml

  1. # 此处省略 redis 连接相关配置
  2. spring:
  3. session:
  4. store-type: redis
复制代码

Spring Security 配置代码示例

  1. @EnableWebSecurity
  2. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  3. @Override
  4. protected void configure(HttpSecurity http) throws Exception {
  5. http
  6. .authorizeRequests()
  7. .antMatchers("/user/**").authenticated()
  8. .antMatchers("/manager/**").hasAnyRole(RoleEnum.MANAGER.getMessage())
  9. .anyRequest().permitAll()
  10. .and().formLogin().loginPage("/login").permitAll()
  11. .and().logout().permitAll()
  12. .and().csrf().disable();
  13. }
  14. }
复制代码

强制退出指定给用户接口

  1. import com.spring4all.bean.ResponseBean;
  2. import com.spring4all.service.UserService;
  3. import lombok.AllArgsConstructor;
  4. import org.springframework.session.FindByIndexNameSessionRepository;
  5. import org.springframework.session.Session;
  6. import org.springframework.session.data.redis.RedisOperationsSessionRepository;
  7. import org.springframework.web.bind.annotation.GetMapping;
  8. import org.springframework.web.bind.annotation.PathVariable;
  9. import org.springframework.web.bind.annotation.RequestMapping;
  10. import org.springframework.web.bind.annotation.RestController;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. import java.util.Map;
  14. @RestController
  15. @AllArgsConstructor
  16. public class UserManageApi {
  17. private final FindByIndexNameSessionRepository<? extends Session> sessionRepository;
  18. private final RedisOperationsSessionRepository redisOperationsSessionRepository;
  19. private final UserService userService;
  20. /**
  21. * 管理指定用户退出登录
  22. * @param userId 用户ID
  23. * @return 用户 Session 信息
  24. */
  25. @PreAuthorize("hasRole('MANAGER')")
  26. @GetMapping("/manager/logout/{userId}")
  27. public ResponseBean data(@PathVariable() Long userId){
  28. // 查询 PrincipalNameIndexName(Redis 用户信息的 key),结合自身业务逻辑来实现
  29. String indexName = userService.getPrincipalNameIndexName(userId);
  30. // 查询用户的 Session 信息,返回值 key 为 sessionId
  31. Map<String, ? extends Session> userSessions = sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, indexName);
  32. // 移除用户的 session 信息
  33. List<String> sessionIds = new ArrayList<>(userSessions.keySet());
  34. for (String session : sessionIds) {
  35. redisOperationsSessionRepository.deleteById(session);
  36. }
  37. return ResponseBean.success(userSessions);
  38. }
  39. }
复制代码

说明 indexName 为 Principal.getName() 的返回值。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持程序员之家。



回复

使用道具 举报