zoukankan      html  css  js  c++  java
  • 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.总结:

    更新当前登录用户的权限列表 ,登出后将释放 ,当再次从数据库获取权限数据时将还原【包括自动登录】 ,因此如果需要持久性的更改权限,

    还需要修改数据库信息
  • 相关阅读:
    Pascal's Triangle II
    Pascal's Triangle
    Best Time to Buy and Sell Stock II
    Best Time to Buy and Sell Stock
    Populating Next Right Pointers in Each Node
    path sum II
    Path Sum
    [转载]小波时频图
    [转载]小波时频图
    [转载]Hilbert变换及谱分析
  • 原文地址:https://www.cnblogs.com/c2g5201314/p/13037147.html
Copyright © 2011-2022 走看看