WHCSRL 技术网

RBAC权限管理简单原理

RBAC

  • role-Base Access Control

    • 基于角色的访问控制
  • 组成

    • User
    • Role
    • Permission
      • 操作
      • 对象
    • user-role映射
    • role-permission映射
  • 安全原则

    • 最小权限原则
    • 责任分离原则
    • 数据抽象原则

数据库

  • user

    • id
    • user_name
    • password
  • role

    • id
    • role_name
  • user_role

    • u_id
    • r_id
  • permission

    • id
    • permission_name
  • role_permission

    • r_id
    • p_id

功能

  • 认证
    • authorization
  • 授权
    • authentication

aop

  • 定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasPermission{
    String value();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 使用注解
@HasPermission("user:delete")
  • 1
  • 解析注解
    • @before
    • @around
@Aspect
@Component
public class PermissionAop{
    @Around("@annotation(xxx.xxx.HasPermission)")
    // 环绕
    public Object around(ProceedingJoinPoint joinPoint){
        // 获取session
        ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpSession session = sra.getRequest().getSession();
        // 获取session中的权限
        List<String> permissions = (List<String>) session.getAttribute("permission");
        // 获取注解内的值
        HasPermission annotation = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(HasPermission.class);
        String value = annotation.value();
        
        boolean contains = permissions.contains(value);
        if(!contains){
            throw new Exception("没有该权限");
        }
        Object object = null;
        object =  joinPoint.process(joinPoint.getArgs());
        return object;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

封装

  • UserNameAndPasswordToken
public class UserNameAndPasswordToken{
    private String username;
    private String password;
    // get set
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • Realm
// 认证和授权的核心
private interface Realm{
    // 认证,查询用户信息
    UserNameAndPasswordToken authentication(String username);
    // 授权,查询权限信息
    PermsisionInfo authorization(String username);

    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • PermissionInfo
// 用于存储权限信息
public class PermissionInfo{
    private List<String> roles;
    private List<String> permissions;
    // get set
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • Subject
@Component
public class Subject{
    
    @Resource
    private Realm realm;
    
    private static Realm myRealm;
    
    // 所有session都存入ONLINE_SESSION
    private static Map<String,HttpSession> ONLINE_SESSION = new HashMap<String,HttpSession>();
    
    @PostConstruct
    public void init(){
        myRealm = realm;
    }

    public static volid login(String name,String pwd){
        UserNameAndPasswordToken token = myRealm.authentication(name);
        String username = token.getUsername();
        boolean usernameIsExist = ONLINE_SESSION.containsKey(username);
        if(usernameIsExist){
            // 踢出重名
            ONLINE_SESSION.get(username).invalidite();
        }
        if(!token.getPassword().equals(pwd)){
            throw new Exception("密码错误");
        }
        getSession().setAttribute("user",username);
        getSession().setAttribute("roles",myRealm.authorization(username).getRoles());
        getSession().setAttribute("permissions",myRealm.authorization(username).getPermissions());
        ONLINE_SESSION.put(username,getSession());
    }
    
    public static HttpSession getSession(){
         // 获取session
        ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpSession session = sra.getRequest().getSession();
        return session;
    }
    
    
    public static Map<String,HttpSession> getOnline(){
        return ONLINE_SESSION;
    }
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

使用封装

// 实现接口Realm
@Component
public class UserRealm implements Realm{
    @Autowrited
    private UserService userService;
    @Autowrited
    private RoleService roleService;
    @Autowrited
    private PermissionService permissionService;
    
    // 认证,查询用户信息
    public UserNameAndPasswordToken authentication(String username){
        if(StringUtils.isEmpty(username)){
            throw new Exception("用户名为空");
        }
        // 使用userService查询用户
        List<Usaer> userByName = userService.findUserByName(username);
        if(userByName==null || userByName.size()==0){
            throw new Exception("用户没有找到");
        }
        
        return new UserNameAndPasswordToken(userByName.get(0).getUsername(),userByName.get(0).getPassword());
    }
    // 授权,查询权限信息
    public PermsisionInfo authorization(String username){
        List<String> permissions =  permissionService.getPermissionsByUserName(username);
        List<String> roles = roleService.getRolesByUserName(username);
        PermissionInfo permissionInfo = new PermissionInfo();
        permissionInfo.setPermissios(permissions);
        permissionInfo.setRoles(roles);
        return permissionInfo;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 登录时调用
Subject.login(username,password);
  • 1

过滤器

// 需要将过滤器加入springboot配置
public class LoginFilter implements Filter{
    
    public String[] ignoreUrl;
    
    public void init(FilterConfig filterConfig) throws ServletException{
        String ignore = filterConfig.getInitParameter("ignore");
        ignoreUrl = ignore.splot(",");
    }
    
    public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain){
        boolean isIgnore = isIgnore(servletRequest);
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        if(isIgnore){
            filterChain.doFilter(servletRequest,servletResponse);
        }else{
            
             HttpSession session = request.getSession();
             Object user = session.getAttribute("user");
             if(user==null){
                 // 未登录
                 // 重定向
                 response.sendRedirect("/");
             }else{
                 filterChain.doFilter(servletRequest,servletResponse);
             }
        }
    }
    
    public boolean isIgnore(HttpServletRequest request){
        for(String ignore: ignoreUrl){
            if(request.getRequestURU().equals(ignore)){
                return true;
            }
        }
        return false;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
推荐阅读