spring security 動態 修改當前登錄用戶的 權限


1.前言

   spring security 可以獲取當前登錄的用戶信息,同時提供了接口 來修改權限列表信息 ,

使用這個方法 ,可以動態的修改當前登錄用戶權限。

  那么問題來了。。。

如果我是管理員 ,如何動態地修改用戶的權限?比如vip權限?

  按照以前的權限使用方法 ,修改數據庫的權限信息后,當前用戶需要重新登錄,才能從數據庫獲取新的權限信息后再更新當前用戶的權限列表,一般是管理員修改權限后,強制用戶重新登錄,

這樣對用戶很不友好 ,使用spring security 可以直接更新當前用戶的權限 ,其實就是重新注冊權限列表信息。

  可是問題又來了。。。

spring security 不是只能修改當前登錄用戶的信息么?那么怎么修改別人的?

  有兩個解決方案:

(1)方案一:管理員在數據庫修改用戶權限數據后,檢查該用戶是否已經登錄,未登錄則操作結束,

  如果已經登錄,則使用websocket通知用戶前端向后端Ajax發送一個修改當前權限的請求。

(2)方案二:管理員在數據庫修改用戶權限數據,檢查該用戶是否已經登錄,未登錄則操作結束,

  如果已經登錄,獲取當前用戶存在內存的session,根據session獲取該用戶的認證信息 ,取出權限列表后對其修改,然后重新注冊權限列表。

2.操作

准備一個配置好的spring boot+ spring security的工程 ,詳細操作這里不演示 ,在我的其他隨筆有詳細記錄

 (1)目錄結構  

 

 (2)添加方法

 

 源碼

package com.example.security5500.controller;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 作為授權類 ,用來動態更新權限
 */
@RestController
public class AuthorityController {

    //添加權限 ,參數是需要新增的權限名
    @RequestMapping("/addAuth")
    public Map<String,Object> addAuth(String authName){
        Map<String,Object> map = new HashMap<>();
        if (StringUtils.isBlank(authName)){
            map.put("data","權限名稱不可空,參數名authName");
            return map;
        }

        try {
            //========================================================
            //這一段僅僅是更新當前登錄用戶的權限列表 ,登出后將釋放 ,當再次從數據庫獲取權限數據時將還原 ,因此如果需要持久性的更改權限,
            // 還需要修改數據庫信息 ,懶得寫 ,這里就不做修改數據庫演示了
            //
            // 得到當前的認證信息
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            //  生成當前的所有授權
            List<GrantedAuthority> updatedAuthorities = new ArrayList<>(auth.getAuthorities());
            // 添加 ROLE_VIP 授權
            updatedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + authName));
            // 生成新的認證信息
            Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), updatedAuthorities);
            // 重置認證信息
            SecurityContextHolder.getContext().setAuthentication(newAuth);
            //========================================================
            map.put("data","權限 "+authName+" 添加成功");
        }catch (Exception e){
            e.printStackTrace();
            map.put("data","權限添加失敗");
        }
        return map;
    }


    //獲取用戶權限信息
    @RequestMapping({"/info"})
    @ResponseBody
    public Object info(@AuthenticationPrincipal Principal principal) {
        return principal;
    }
    /*
    {"authorities":[{"authority":"admin"},{"authority":"user"}],
    "details":{"remoteAddress":"0:0:0:0:0:0:0:1","sessionId":"1F57B8E39C5D1DB1F875D57D533DB982"},
    "authenticated":true,"principal":{"password":null,"username":"xi","authorities":[{"authority":"admin"},
    {"authority":"user"}],"accountNonExpired":true,"accountNonLocked":true,
    "credentialsNonExpired":true,"enabled":true},"credentials":null,"name":"xi"}

     */


    //http://localhost:5500/addAuth?authName=love1
    //http://localhost:5500/info


}
View Code

 

 

(3)攔截位置 ,需要權限  ROLE_love1 才可以訪問

 

 3.測試

 

 

 啟動工程

 (1)訪使用一個 有 權限  ROLE_love1 的賬戶

username = cen

password = 11

訪問網址 http://localhost:5500/home

 

 點擊登錄

顯然可以正常運行 

訪問網址  http://localhost:5500/info  查看當前登錄用戶的認證信息 ,是有 ROLE_love1 權限的

 

 

 

 (2)訪使用一個 沒有 權限  ROLE_love1 的賬戶

 

username = yue

password = 11

訪問網址 http://localhost:5500/home

選擇  “記住我”  ,可以自動登錄

 

 提示 403 ,

 

 訪問網址  http://localhost:5500/info  查看當前登錄用戶的認證信息 ,是 沒有 ROLE_love1 權限的

 

 

現在添加權限 

訪問網址   http://localhost:5500/addAuth?authName=love1

 

 

  再次 訪問網址  http://localhost:5500/info  查看當前登錄用戶的認證信息 ,發現 有 ROLE_love1 權限了

 

 

 再次 訪問網址 http://localhost:5500/home發現訪問成功啦

 

 

(2)那么現在問題來了,現在是開啟了自動登錄模式 ,那么關閉瀏覽器后 cookie是否會刪除? 如果不刪除 ,新加的權限是否會刪除?

繼續上面yue的登錄頁面  直接關閉瀏覽器,再訪問  http://localhost:5500/home

發現被攔截進入 登錄頁面了 

 

 難道被強制登出了?

不 ,查看cookie ,並沒有被刪除

 

 

繼續 訪問  http://localhost:5500/hai  ,發現是已經自動登錄了

 

 

 於是查看 認證信息 ,訪問網址  http://localhost:5500/info

 

 發現 ROLE_love1 權限被清除了

 

 

(3)為什么會這樣?

有兩個猜測 :

猜測一:在第一次登錄時 ,沒有權限的 認證信息已經存在cookie ,不再修改,自動登錄不再從數據庫獲取權限信息。

猜測二 : 即便是自動登錄 ,每次登錄的都會從數據庫獲取用戶信息並更新 ,以前登錄時存在內存的信息會在瀏覽器銷毀后釋放。

證明:

我在注冊權限的地方加了指令將添加到注冊列表的權限名打印

 

 源碼

package com.example.security5500.securityConfig;


import com.example.security5500.entitis.tables.TUser;
import com.example.security5500.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

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

@Service
public class DbUserDetailsService implements UserDetailsService {

   @Autowired
   private UserService userService;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根據用戶名查詢用戶信息
        TUser tUser = userService.getByUsername(username);
        if (tUser == null){
            throw new UsernameNotFoundException("用戶不存在!");
        }
        //權限設置
//        List<GrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
        List<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
        String role = tUser.getRole();
        //分割權限名稱,如 user,admin
        String[] roles = role.split(",");
        System.out.println("注冊該賬戶權限");
        for (String r :roles){
            System.out.println(r);
            //添加權限
            simpleGrantedAuthorities.add(new SimpleGrantedAuthority(r));
        }

//        simpleGrantedAuthorities.add(new SimpleGrantedAuthority("USER"));
        /**
         * 創建一個用於認證的用戶對象並返回,包括:用戶名,密碼,角色
         */
        //輸入參數
        return new org.springframework.security.core.userdetails.User(tUser.getUsername(), tUser.getPsw(), simpleGrantedAuthorities);
    }

}
View Code

 

自動登錄后

控制台打印的結果:

 

 

因此 ,猜測二是正確的  。

 

 

4.總結:

更新當前登錄用戶的權限列表 ,登出后將釋放 ,當再次從數據庫獲取權限數據時將還原【包括自動登錄】 ,因此如果需要持久性的更改權限,

還需要修改數據庫信息

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM