Spring Security 強制退出指定使用者

yifanwu發表於2021-09-09

應用場景

最近社群總有人發文章帶上小廣告,嚴重影響社群氛圍,好氣!對於這種型別的使用者,就該永久拉黑!

社群的安全框架使用了 spring-securityspring-session,登入狀態 30 天有效,session 資訊是存在 redis 中,如何優雅地處理這些不老實的使用者呢?

首先,簡單劃分下使用者的許可權:

  • 管理員(ROLE_MANAGER):基本操作 + 管理操作

  • 普通使用者(ROLE_USER):基本操作

  • 拉黑使用者(ROLE_BLACK):不允許登入

然後,拉黑指定使用者(ROLE_USER -> ROLE_BLACK),再強制該使用者退出即可(刪除該使用者在 redis 中 session 資訊)。

專案相關依賴及配置

Maven 依賴

        <!-- 安全 Security --&gt
        
            org.springframework.boot
            spring-boot-starter-security
        

        <!-- Redis --&gt
        
            org.springframework.boot
            spring-boot-starter-data-redis
        

        <!-- Spring Session Redis --&gt
        
            org.springframework.session
            spring-session-data-redis
        

Spring Session 策略配置 application.yml

# 此處省略 redis 連線相關配置spring:
  session:
    store-type: redis

Spring Security 配置程式碼示例

@EnableWebSecuritypublic 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();
    }

}

強制退出指定給使用者介面

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@AllArgsConstructorpublic 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 userSessions = sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, indexName);        // 移除使用者的 session 資訊
        List sessionIds = new ArrayList(userSessions.keySet());        for (String session : sessionIds) {
            redisOperationsSessionRepository.deleteById(session);
        }        return ResponseBean.success(userSessions);
    }

}

說明 indexName 為  Principal.getName()  的返回值。

相關文件


作者:Anoyi
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2157/viewspace-2802976/,如需轉載,請註明出處,否則將追究法律責任。

相關文章