Spring Security force quit specified user

Application scenarios

Recently, there are always people in the community posting articles with small advertisements, which seriously affects the atmosphere of the community. Good luck! For this type of user, it should be permanently blocked!

The community's security framework uses  spring-security and  spring-session, the login status is valid for 30 days, and the session information is stored in redis. How to gracefully handle these dishonest users?

First, simply divide the permissions of the user:

  • Administrator (ROLE_MANAGER): basic operations + management operations
  • Ordinary user (ROLE_USER): basic operations
  • Block user (ROLE_BLACK): login is not allowed

Then, block the specified user (ROLE_USER -> ROLE_BLACK), and then force the user to exit (delete the user's session information in redis).

Project related dependencies and configuration

Maven dependencies

        <!-- 安全 Security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- Redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- Spring Session Redis -->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

Spring Session Policy Configuration application.yml

# 此处省略 redis 连接相关配置
spring:
  session:
    store-type: redis

Spring Security configuration code example

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/user/**").authenticated()
                .antMatchers("/manager/**").hasAnyRole(RoleEnum.MANAGER.getMessage())
                .anyRequest().permitAll()
                .and().formLogin().loginPage("/login").permitAll()
                .and().logout().permitAll()
                .and().csrf().disable();
    }

}

Force quit assigned to user interface

import com.spring4all.bean.ResponseBean;
import com.spring4all.service.UserService;
import lombok.AllArgsConstructor;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RestController
@AllArgsConstructor
public class UserManageApi {

    private final FindByIndexNameSessionRepository<? extends Session> sessionRepository;

    private final RedisOperationsSessionRepository redisOperationsSessionRepository;

    private final UserService userService;

    /**
     * 管理指定用户退出登录
     * @param userId 用户ID
     * @return 用户 Session 信息
     */
    @PreAuthorize("hasRole('MANAGER')")
    @GetMapping("/manager/logout/{userId}")
    public ResponseBean data(@PathVariable() Long userId){
        // 查询 PrincipalNameIndexName(Redis 用户信息的 key),结合自身业务逻辑来实现
        String indexName = userService.getPrincipalNameIndexName(userId);
        // 查询用户的 Session 信息,返回值 key 为 sessionId
        Map<String, ? extends Session> userSessions = sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, indexName);
        // 移除用户的 session 信息
        List<String> sessionIds = new ArrayList<>(userSessions.keySet());
        for (String session : sessionIds) {
            redisOperationsSessionRepository.deleteById(session);
        }
        return ResponseBean.success(userSessions);
    }

}

Note that indexName is the return value of Principal.getName().

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324652363&siteId=291194637