fibman 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b57c1d03d4c61992edcbd96b4d10b52790b5f090
4
+ data.tar.gz: 1acde7737f7b0dffe4fd8670615d20d1892b12e9
5
+ SHA512:
6
+ metadata.gz: 0626124586074c74cbc5dba0e71984afd9267259256aaf0a682536e796c835bde87534851c85de29333050cfd8369ccc6a04d9e1cd8e46fad7d3d3fe1cf70694
7
+ data.tar.gz: 1533db7379c16fe4feeab3335db101a0ebe06c2ea27b2eeb1af3a897c5aeedd99b7d7c91b8771b85ca3f31b92480fbf4ebe336e1a09b20e2868f39a801aacfa1
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rubocop.yml ADDED
@@ -0,0 +1,35 @@
1
+ ###########################
2
+ # Configuration for rubocop
3
+ # in .rubocop.yml
4
+ # Most of these are disabling existing cops, primarily
5
+ # due to a smattering of different styles and loose
6
+ # guidlines for contributions.
7
+ #
8
+ # Any of these may be changed.
9
+ AllCops:
10
+ Exclude:
11
+ - 'examples/*.rb'
12
+
13
+ Style/SpaceInsideBlockBraces:
14
+ Enabled: false
15
+
16
+ Metrics/ClassLength:
17
+ Enabled: false
18
+
19
+ Metrics/LineLength:
20
+ Max: 200
21
+
22
+ Metrics/MethodLength:
23
+ Max: 20
24
+
25
+ Style/SignalException:
26
+ Enabled: false
27
+
28
+ Style/StringLiterals:
29
+ Enabled: false
30
+
31
+ Style/AsciiComments:
32
+ Enabled: false
33
+
34
+ Metrics/AbcSize:
35
+ Enabled: false
data/.simplecov ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ if ENV["COVERAGE"]
3
+ SimpleCov.profiles.define 'fib' do
4
+ add_filter "/vendor/"
5
+
6
+ add_group 'Libraries', 'lib'
7
+ end
8
+
9
+
10
+ SimpleCov.start "request_pool"
11
+ puts "required simplecov"
12
+ end
13
+
14
+ # require 'request_pool'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 Warrenoo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,181 @@
1
+ # Fibman
2
+ [<img src="https://fury-badge.herokuapp.com/rb/fibman.png" alt="Gem Version" />](http://badge.fury.io/rb/fibman)
3
+
4
+ [Fibman](https://github.com/Warrenoo/fibman) 是提供系统权限管理验证的模块
5
+
6
+
7
+ ## 功能
8
+
9
+ - 支持持久化对象权限
10
+ - 定义多种权限维度, 高自由度的权限验证
11
+ - 快速定义权限管理对象,注入完善的管理模块
12
+ - 支持对象间权限依赖关系的拓展
13
+ - 支持权限与权限间的绑定
14
+ - 全方位的权限校验支持
15
+ - 支持单系统多权限模块的组织结构
16
+
17
+ ## 安装
18
+
19
+ 添加到 Gemfile:
20
+
21
+ gem 'fibman', '~> 2.0'
22
+
23
+ 并运行 `bundle install` 命令。
24
+
25
+ ## 开始
26
+
27
+ ### 1. 初始化一个权限模块
28
+
29
+ Fibman.new 作为创建权限管理系统的入口,需要定义一个名称和唯一的key
30
+
31
+ Fibman 初始化后可以进行权限的定义与管理
32
+
33
+ 可以在一个系统中定义多个Fibman对象,分别定义不同的权限类型,并管理不同的模块
34
+
35
+ ```ruby
36
+ demo_fib = Fibman.new(:demo, "权限系统示例")
37
+ ```
38
+
39
+ ### 2. 配置持久化连接
40
+
41
+ Fibman 使用 Redis 提供数据持久化服务,所以需要配置 redis 的连接对象,默认使用`gem redis-rb`中的api
42
+
43
+ ```
44
+ demo_fib.configure { |c| c.redis = Redis.current }
45
+ ```
46
+
47
+ ### 3. 权限定义
48
+
49
+ 在Fibman中,支持三种权限维度的设定
50
+
51
+ - URL 设定某个URL
52
+ - KEY 设定某个自定义Key
53
+ - ACTION MVC框架中,设定Controller层具体Action
54
+
55
+ 通过调用`build`方法构建当前权限系统的权限集
56
+
57
+ 使用`add`方法来定义权限集
58
+
59
+ 每个权限集可以包含若干具体的权限维度,创建权限集后会默认包含一个和权限集key相同的KEY类型权限,主要用来进行权限集查询。
60
+
61
+ 权限集与权限集直接可以进行绑定。当A权限集绑定了B权限集,目标对象拥有A权限集时,则默认也拥有B权限集。绑定关系可设定多个。
62
+
63
+ ```
64
+ demo_fib.build do
65
+ # 通过参数定义
66
+ # action 定义action类权限
67
+ # url 定义url类权限
68
+ # key 定义key类权限
69
+ # bind 绑定其他权限集
70
+ # display 是否公开
71
+ add :permission1, "Permission1",
72
+ action: [[DemoController, :index]],
73
+ url: ["demo/list", "demo/topic"],
74
+ key: [:permission1_key1, :permission1_key2],
75
+ bind: :permission2,
76
+ display: true
77
+
78
+ # 或者
79
+ # 通过proc定义
80
+ add :permission1, "Permission1" do
81
+ def_action DemoController, :show do |user, request|
82
+ # 扩展权限验证,额外进行权限判断
83
+ user.demo.id == request.params[:id]
84
+ end
85
+
86
+ def_url "demo/list" do |user, request|
87
+ # True or False
88
+ end
89
+
90
+ def_key :permission1_key1 do |user, obj|
91
+ # obj为进行key判断时自定义传入的对象类型
92
+ end
93
+
94
+ # 开关是否公开
95
+ display_on
96
+ # or
97
+ display_off
98
+
99
+ # 绑定其他权限集
100
+ bind_permission :permission2
101
+ end
102
+ end
103
+ ```
104
+
105
+ ### 4. 设定权限管理目标模块
106
+
107
+ 该功能当前只支持Rails框架
108
+
109
+ 在需要被管理的ActiveRecord::Base子类中调用`fib_targeter! :demo`指定该类属于之前定义的权限系统。
110
+
111
+ ```ruby
112
+ class Role < ActiveRecord::Base
113
+ fib_targeter! :demo
114
+ end
115
+
116
+ class User < ActiveRecord::Base
117
+ belongs_to :role
118
+
119
+ # 指定该类的权限继承于某一关系对象, 需要该对象的类也定义了`fib_targeter! :demo`
120
+ # 如没有指定inherit,默认继承于demo_fib, 权限范围为全部权限集
121
+ fib_targeter! :demo, inherit: :role
122
+ end
123
+ ```
124
+
125
+ 然后当前类对象便可以进行权限管理
126
+ ```ruby
127
+ u = User.first
128
+
129
+ u.permissions # 获取权限
130
+ u.permissions_info # 获取权限信息 [[:key, :name]]
131
+ u.permissions_scope # 获取权限范围
132
+ u.save_permissions # 保存当前权限
133
+ u.create_permissions(*keys) # 通过传入的keys创建权限,保存
134
+ u.new_permissions(*keys) # 通过传入的keys创建权限,不保存
135
+ u.add_permissions(*keys) # 添加权限,保存
136
+ u.del_permissions(*keys) # 删除权限,保存
137
+ u.clear_permissions # 清空权限,保存
138
+ ```
139
+
140
+ ### 5. 设定权限验证入口
141
+
142
+ 该功能当前只支持Rails框架
143
+
144
+ 在需要对权限进行验证的ActionController::Base子类中调用`fib_controller! :demo`指定从该入口进行权限验证
145
+
146
+ 所有通过该入口进入的请求都会对`current_user`进行权限系统验证。请确保在该Controller中可以调用`current_user`方法
147
+
148
+ ```ruby
149
+ class DemoController < ActionController::Base
150
+ fib_controller! :demo
151
+
152
+ def current_user
153
+ # 查找当前用户的方法
154
+ end
155
+ end
156
+ ```
157
+
158
+ ### 6. 权限验证说明
159
+
160
+ 如果当前请求的action和url并未在权限系统中定义,则会默认通过验证,并提示当前请求权限未被定义
161
+
162
+ 如果当前请求的action和url已定义但当前用户不拥有该权限,则返回401
163
+
164
+ 对于key类型的权限,提供了一组dsl方法进行验证
165
+
166
+ ```erb
167
+ <% if can?(:permission1_key2) && can?(:permission1_key1, obj) %>
168
+ <p>1</p>
169
+ <% elsif cannot? :permission1 %>
170
+ <p>2</p>
171
+ <% end %>
172
+ ```
173
+
174
+ ## TODO
175
+
176
+ - 优化查询
177
+
178
+ ## BUG?
179
+
180
+ 如果发现任何问题欢迎[提交Issue](https://github.com/Warrenoo/fibman/issues)或者Fork项目并创建Pull Requests
181
+
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env rake
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks.'
7
+ end
8
+
9
+ # === Bundler ===
10
+
11
+ Bundler::GemHelper.install_tasks
12
+
13
+ # === RSpec ===
14
+
15
+ require 'rspec/core/rake_task'
16
+
17
+ RSpec::Core::RakeTask.new :spec
18
+
19
+ # === RuboCop ===
20
+
21
+ require 'rubocop/rake_task'
22
+
23
+ RuboCop::RakeTask.new(:rubocop) do |task|
24
+ task.requires << 'rubocop-rspec'
25
+
26
+ # Don't abort Rake on failure.
27
+ task.fail_on_error = false
28
+ end
29
+
30
+ # === Configuration ===
31
+
32
+ # Run all specs and RuboCop as default task.
33
+ task default: [:spec, :rubocop]
34
+
35
+ task test: [:spec, :rubocop]
data/fibman.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fibman/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'fibman'
8
+ spec.version = Fibman::VERSION
9
+ spec.authors = ['Warrenoo']
10
+ spec.email = ['541991a@gmail.com']
11
+ spec.summary = '权限管理'
12
+ spec.description = '多模块持久化权限管理系统'
13
+ spec.license = 'MIT'
14
+ spec.homepage = 'https://github.com/Warrenoo/fib'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'activesupport', '~> 0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.7'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ spec.add_development_dependency 'rubocop', '~> 0'
26
+
27
+ spec.add_development_dependency 'rspec', '~> 0'
28
+ spec.add_development_dependency 'rubocop-rspec', '~> 0'
29
+ spec.add_development_dependency 'simplecov', '~> 0'
30
+ end
@@ -0,0 +1,35 @@
1
+ module Fibman
2
+ module Additions
3
+ module ContainerAddition
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :__fib_container, instance_writer: false
8
+ class_attribute :__fib_inherit, instance_writer: false
9
+ end
10
+
11
+ def fib_container
12
+ self.class.fib_container
13
+ end
14
+
15
+ def fib_inherit
16
+ if __fib_inherit && respond_to?(__fib_inherit) && (obj=send(__fib_inherit))
17
+ obj
18
+ else
19
+ fib_container
20
+ end
21
+ end
22
+
23
+ class_methods do
24
+ def fib_container
25
+ return unless __fib_container
26
+ self.__fib_container = __fib_container.is_a?(Fibman::Container) ? __fib_container : (Fibman.ls.find { |c| c.key == __fib_container } || __fib_container)
27
+ end
28
+
29
+ def fib_container= key
30
+ self.__fib_container = key
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,24 @@
1
+ module Fibman
2
+ module Additions
3
+ module ControllerDslAddition
4
+ extend ActiveSupport::Concern
5
+ class_methods do
6
+ def fib_controller! key
7
+ include Fibman::Additions::RailsControllerAddition
8
+ self.fib_container = key
9
+ end
10
+ end
11
+ end
12
+
13
+ module TargeterDslAddition
14
+ extend ActiveSupport::Concern
15
+ class_methods do
16
+ def fib_targeter! key, options={}
17
+ include Fibman::Additions::TargeterAddition
18
+ self.fib_container = key
19
+ self.__fib_inherit = options[:inherit] if options[:inherit]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,67 @@
1
+ module Fibman
2
+ module Additions
3
+ module RailsControllerAddition
4
+ extend ActiveSupport::Concern
5
+ include Fibman::Additions::ContainerAddition
6
+
7
+ included do
8
+ before_action :fib_include_validation
9
+ helper_method :can?, :cannot?
10
+
11
+ delegate :permissions, to: :current_user
12
+
13
+ rescue_from Fibman::UnPassPermissionValidation, with: :handle_fib_permission_error
14
+ end
15
+
16
+ def can? key, obj=nil
17
+ key_element = permissions.find_key(key)
18
+ key_element.present? && key_element.pass_condition?(current_user, obj)
19
+ end
20
+
21
+ def cannot? key, obj=nil
22
+ !can?(key, obj)
23
+ end
24
+
25
+ private
26
+
27
+ def handle_fib_permission_error
28
+ render status: 401, plain: "No permission" and return
29
+ end
30
+
31
+ # 验证url权限
32
+ def fib_url_validation
33
+ url_element = permissions.find_url(request.path)
34
+
35
+ unless url_element && url_element.pass_condition?(current_user, request)
36
+ raise Fibman::UnPassPermissionValidation
37
+ end
38
+ end
39
+
40
+ # 验证action权限
41
+ def fib_action_validation
42
+ controller = self.class.name
43
+ action = self.action_name
44
+
45
+ action_element = permissions.find_action(controller, action)
46
+
47
+ unless action_element && action_element.pass_condition?(current_user, request)
48
+ raise Fibman::UnPassPermissionValidation
49
+ end
50
+ end
51
+
52
+ # 如果该请求访问未在权限系统中设置
53
+ # 通过并提示
54
+ def fib_include_validation
55
+ has_action = fib_container.permissions.find_action(self.class.name, self.action_name).present?
56
+ has_url = fib_container.permissions.find_url(request.path).present?
57
+
58
+ fib_action_validation if has_action
59
+ fib_url_validation if has_url
60
+
61
+ unless has_action || has_url
62
+ # TODO 进行提示 策略待定
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,64 @@
1
+ module Fibman
2
+ module Additions
3
+ module TargeterAddition
4
+ extend ActiveSupport::Concern
5
+ include Fibman::Additions::ContainerAddition
6
+
7
+ delegate :permissions_info, to: :permissions
8
+
9
+ # 最终权限来源自于权限范围与持久化权限的并集
10
+ def permissions
11
+ @permissions ||= permissions_scope & (get_persistence_permissions || Fibman::PermissionsCollection.new)
12
+ end
13
+
14
+ def permissions_scope
15
+ fib_inherit.permissions
16
+ end
17
+
18
+ def save_permissions
19
+ fib_container.fpa.save fib_redis_key, permissions.keys
20
+ end
21
+
22
+ def create_permissions *permission_keys
23
+ clear_permissions
24
+ new_permissions permission_keys
25
+ save_permissions
26
+ end
27
+
28
+ def new_permissions *permission_keys
29
+ permission_keys = [permission_keys].flatten
30
+ @permissions = fib_container.permissions.extract_by_keys permission_keys
31
+ end
32
+
33
+ def add_permissions *permission_keys
34
+ new_permissions = fib_container.permissions.extract_by_keys permission_keys
35
+ @permissions += new_permissions
36
+ save_permissions
37
+ end
38
+
39
+ def del_permissions *permission_keys
40
+ del_permissions = fib_container.permissions.extract_by_keys permission_keys
41
+ @permissions -= del_permissions
42
+ save_permissions
43
+ end
44
+
45
+ def clear_permissions
46
+ fib_container.fpa.clear fib_redis_key
47
+ @permissions = nil
48
+ end
49
+
50
+ def get_persistence_permissions
51
+ fib_container.restore_permissions(fib_redis_key)
52
+ end
53
+
54
+ def fib_redis_key
55
+ "Fibman:#{fib_container.key}:#{self.class.name}:#{fib_identify}"
56
+ end
57
+
58
+ def fib_identify
59
+ raise UnSetTargeterIdentify, "Please rewrite [fib_identify] method and set only sign in #{self.class.name}" unless respond_to? :id
60
+ id
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,9 @@
1
+ module Fibman
2
+ class Config
3
+ attr_accessor :redis
4
+
5
+ def configure
6
+ yield(self)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,48 @@
1
+ module Fibman
2
+ class Container
3
+ extend Forwardable
4
+
5
+ attr_accessor :name, :key, :permissions, :config, :fpa
6
+
7
+ def_delegator :permissions, :permissions_info
8
+ def_delegator :config, :configure, :config_configure
9
+
10
+ cattr_accessor(:containers) { [] }
11
+
12
+ def initialize key, name
13
+ @key = key
14
+ @name = name
15
+ @permissions = Fibman::PermissionsCollection.new
16
+ @config = Fibman::Config.new
17
+ @fpa = Fibman::Fpa.new
18
+
19
+ @permissions.container = self
20
+ self.class.containers << self
21
+ end
22
+
23
+ def configure &block
24
+ config_configure &block
25
+ loading!
26
+ end
27
+
28
+ def loading!
29
+ load_fpa
30
+ end
31
+
32
+ def load_fpa
33
+ fpa.redis = config.redis
34
+ end
35
+
36
+ def build &block
37
+ permissions.instance_exec &block
38
+ end
39
+
40
+ def restore_permissions redis_key
41
+ return unless keys = fpa.get(redis_key)
42
+ permissions.extract_by_keys keys
43
+ end
44
+
45
+ class << self; alias_method :ls, :containers; end
46
+ end
47
+ end
48
+
@@ -0,0 +1,37 @@
1
+ module Fibman
2
+ class Element
3
+ attr_reader :type, :core, :condition, :permission_key
4
+ TYPE = %w(key action url).freeze
5
+
6
+ def initialize type, core, condition=->(*args){}
7
+ raise UnValidElementType, "current type -> #{type}, type need in (#{TYPE.join(", ")})!" unless TYPE.include? type
8
+ @type = type
9
+ @core = core
10
+ raise ParameterIsNotValid, "Condition must belong to Proc!" unless condition.nil? || condition.is_a?(Proc)
11
+ @condition = condition || ->(*args){}
12
+ end
13
+
14
+ def set_permission permission
15
+ @permission_key = permission.is_a?(Fibman::Permission) ? permission.key : permission
16
+ end
17
+
18
+ def pass_condition? *args
19
+ return true if condition.nil?
20
+ condition[*args] != false
21
+ end
22
+
23
+ class << self
24
+ def create_key key, &block
25
+ new "key", key, block
26
+ end
27
+
28
+ def create_action controller, action, &block
29
+ new "action", {controller: controller.to_s, action: action.to_s}, block
30
+ end
31
+
32
+ def create_url url, &block
33
+ new "url", url, block
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,123 @@
1
+ # Element对象集合
2
+ # 将element的三种type拆分存储
3
+ # keys: key类型element hash
4
+ # actions: action类型element {controller_name: hash}
5
+ # urls: url类型element 以'/'分割的字典树
6
+ # 使用lazy_build方式生成keys actions urls,只在查询时构建
7
+ # mutex 为 true 时需要重新build
8
+ module Fibman
9
+ class ElementPackage
10
+ attr_reader :keys, :actions, :urls, :origin_elements, :mutex
11
+
12
+ def initialize elements=[]
13
+
14
+ @keys = {}
15
+ @actions = {}
16
+ @urls = Fibman::Trie.new('.', nil)
17
+ @origin_elements = elements.group_by{ |e| e.type }
18
+
19
+ rebuild
20
+ end
21
+
22
+ def set element
23
+ raise ParameterIsNotValid, "param must be Element" unless element.is_a?(Fibman::Element)
24
+
25
+ origin_elements[element.type] ||= []
26
+ origin_elements[element.type] |= [element]
27
+
28
+ rebuild
29
+ end
30
+
31
+ alias_method :<<, :set
32
+
33
+ def mset *elements
34
+ elements.flatten.each do |e|
35
+ next unless e.is_a?(Fibman::Element)
36
+ set e
37
+ end
38
+ end
39
+
40
+ alias_method :append, :mset
41
+
42
+ def + package
43
+ self.class.new (origin_elements.values.flatten + package.origin_elements.values.flatten).uniq
44
+ end
45
+
46
+ def find_key k
47
+ lazy_build
48
+ keys[k.to_sym]
49
+ end
50
+
51
+ def find_action controller, action
52
+ lazy_build
53
+ actions&.dig(controller.to_s, action.to_s)
54
+ end
55
+
56
+ def find_url url
57
+ lazy_build
58
+ urls&.dig(*url.gsub(/^\/|\/$/, "").split(/\//))
59
+ end
60
+
61
+ def build
62
+ build_keys
63
+ build_actions
64
+ build_urls
65
+ end
66
+
67
+ def lazy_build
68
+ return if !mutex
69
+
70
+ build
71
+ finish_build
72
+ end
73
+
74
+ def finish_build
75
+ @mutex = false
76
+ end
77
+
78
+ def rebuild
79
+ @mutex = true
80
+ end
81
+
82
+ private
83
+
84
+ def build_keys
85
+ return unless origin_elements.has_key? 'key'
86
+
87
+ origin_elements['key'].each { |e| keys[e.core] = e }
88
+ end
89
+
90
+ def build_actions
91
+ return unless origin_elements.has_key? 'action'
92
+
93
+ origin_elements['action'].each do |e|
94
+ next unless e.core.is_a? Hash
95
+
96
+ key = e.core[:controller].to_s
97
+ actions[key] ||= {}
98
+ actions[key][e.core[:action].to_s] = e
99
+ end
100
+ end
101
+
102
+ def build_urls
103
+ return unless origin_elements.has_key? 'url'
104
+
105
+ origin_elements['url'].each do |e|
106
+ next unless e.core.is_a? String
107
+
108
+ # 过滤首尾 / 并以 / 分割
109
+ split_url = e.core.gsub(/^\/|\/$/, "").split(/\//)
110
+ split_url.each_with_index.reduce(urls) do |i, (j, index)|
111
+ t = i.add_sub j, (index == split_url.size - 1 ? e : nil)
112
+ t
113
+ end
114
+ end
115
+ end
116
+
117
+ class << self
118
+ def merge *packages
119
+ new (packages.reduce([]) { |a, e| a + e.origin_elements.values.flatten }).uniq
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,12 @@
1
+ module Fibman
2
+ class UnValidElementType < RuntimeError; end
3
+ class UnDefinedModel < RuntimeError; end
4
+ class MissParameter < RuntimeError; end
5
+ class ParameterIsNotValid < RuntimeError; end
6
+ class RoleIsNotFind < RuntimeError; end
7
+ class UserClassIsNotFind < RuntimeError; end
8
+ class PermissionIsNotFind < RuntimeError; end
9
+ class RpaIsNotHandle < RuntimeError; end
10
+ class UnPassPermissionValidation < RuntimeError; end
11
+ class UnSetTargeterIdentify < RuntimeError; end
12
+ end
data/lib/fibman/fpa.rb ADDED
@@ -0,0 +1,23 @@
1
+ # Fibman Persistence Adapter
2
+ module Fibman
3
+ class Fpa
4
+ attr_accessor :redis
5
+
6
+ def initialize redis=nil
7
+ @redis = redis
8
+ end
9
+
10
+ def save redis_key, content
11
+ redis.sadd redis_key, content
12
+ end
13
+
14
+ def get redis_key
15
+ return nil unless redis.exists(redis_key)
16
+ redis.smembers(redis_key).map(&:to_sym)
17
+ end
18
+
19
+ def clear redis_key
20
+ redis.del redis_key
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,63 @@
1
+ # Permission Particle
2
+ module Fibman
3
+ class Permission
4
+ extend Forwardable
5
+
6
+ attr_reader :key, :name, :package, :bind, :display
7
+ attr_accessor :container
8
+
9
+ def_delegators :package, :append
10
+
11
+ def initialize key, options={}
12
+ @key = key.to_sym
13
+ @name = options[:name] || key.to_s
14
+ @package = options[:package] || Fibman::ElementPackage.new
15
+ @bind = options[:bind] || []
16
+ @display = options.key?(:display) ? options[:display] : true
17
+ end
18
+
19
+ def bind_packages
20
+ return [] unless bind.present? || container.present?
21
+
22
+ packages = []
23
+ bind.each do |b|
24
+ p = container.permissions.permissions[b]
25
+ next unless p.present?
26
+ packages << p.package
27
+ packages << p.bind_packages
28
+ end
29
+ packages.flatten
30
+ end
31
+
32
+ def def_action controller, action, &block
33
+ @package << Fibman::Element.create_action(controller, action, &block)
34
+ end
35
+
36
+ def def_url url, &block
37
+ @package << Fibman::Element.create_url(url, &block)
38
+ end
39
+
40
+ def def_key key, &block
41
+ @package << Fibman::Element.create_key(key, &block)
42
+ end
43
+
44
+ def display_on
45
+ @display = true
46
+ end
47
+
48
+ def display_off
49
+ @display = false
50
+ end
51
+
52
+ def bind_permission *permission_keys
53
+ @bind << permission_keys.flatten.map(&:to_sym)
54
+ @bind.flatten!.uniq!
55
+ end
56
+
57
+ def inject_elements_permission
58
+ package.origin_elements.values.flatten.each do |e|
59
+ e.set_permission self
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,135 @@
1
+ module Fibman
2
+ class PermissionsCollection
3
+ extend Forwardable
4
+
5
+ attr_reader :permissions, :package
6
+ attr_accessor :container
7
+
8
+ # 通过package 快速查询权限
9
+ def_delegators :package, :find_key, :find_url, :find_action
10
+
11
+ def initialize
12
+ @permissions = {}
13
+ @package = Fibman::ElementPackage.new
14
+ end
15
+
16
+ def permissions_info
17
+ permissions.values.select { |v| v.display }
18
+ .map { |v| [v.key, v.name] }
19
+ end
20
+
21
+ def keys
22
+ permissions.keys
23
+ end
24
+
25
+ def set permission
26
+ raise ParameterIsNotValid, "set method can't accept expect permission object" unless permission.is_a?(Fibman::Permission)
27
+ raise ParameterIsNotValid, "permission key #{permission.key} is exist" if permissions.has_key? permission.key
28
+
29
+ mset permission
30
+ end
31
+
32
+ alias_method :<<, :set
33
+
34
+ def mset *permissions
35
+ permissions.flatten.each do |p|
36
+ next unless p.is_a?(Fibman::Permission)
37
+ @permissions[p.key] = p
38
+ end
39
+ build_package
40
+ end
41
+
42
+ alias_method :append, :mset
43
+
44
+ def empty?
45
+ permissions.keys.size == 0
46
+ end
47
+
48
+ def permission_packages
49
+ (permissions.values.map(&:package) + permissions.values.map(&:bind_packages)).flatten.uniq
50
+ end
51
+
52
+ def build_package
53
+ @package = Fibman::ElementPackage.merge *permission_packages
54
+ end
55
+
56
+ def + permission_collection
57
+ raise ParameterIsNotValid, "must be permission_collection" unless permission_collection.is_a?(Fibman::PermissionsCollection)
58
+
59
+ current_permission_values = permissions.values
60
+ build_new { append *(current_permission_values | permission_collection.permissions.values).flatten }
61
+ end
62
+
63
+ alias_method :|, :+
64
+
65
+ def - permission_collection
66
+ raise ParameterIsNotValid, "must be permission_collection" unless permission_collection.is_a?(Fibman::PermissionsCollection)
67
+
68
+ current_permission_values = permissions.values
69
+ build_new { append *(current_permission_values - permission_collection.permissions.values).flatten }
70
+ end
71
+
72
+ def & permission_collection
73
+ raise ParameterIsNotValid, "must be permission_collection" unless permission_collection.is_a?(Fibman::PermissionsCollection)
74
+
75
+ current_permission_values = permissions.values
76
+ build_new { append *(current_permission_values & permission_collection.permissions.values).flatten }
77
+ end
78
+
79
+ def extract_by_keys keys
80
+ Fibman::PermissionsCollection.build_by_permissions select_permissions_by_keys(keys)
81
+ end
82
+
83
+ def select_permissions_by_keys keys
84
+ permissions.select { |k, v| keys.include? k }.values
85
+ end
86
+
87
+ def build_new &block
88
+ self.class.new.tap { |n| n.instance_exec(&block) if block_given? }
89
+ end
90
+
91
+ def add key, name="", options={}, &block
92
+ return unless key.present?
93
+
94
+ keys = [options[:key] || []].flatten
95
+ urls = [options[:url] || []].flatten
96
+ bind = [options[:bind] || []].flatten
97
+ actions = options[:action] || []
98
+ display = options[:display] if options.key? :display
99
+
100
+ # 构建权限对象
101
+ permission = Fibman::Permission.new key, name: name
102
+
103
+ # 默认创建一个与permission key相同的element key类型
104
+ permission.append Fibman::Element.create_key key
105
+ permission.append keys.map{ |k| Fibman::Element.create_key k }
106
+
107
+ permission.append urls.map{ |u| Fibman::Element.create_url u }
108
+ permission.append actions.map{ |a|
109
+ controller = a.shift
110
+ a.map { |action| Fibman::Element.create_action controller, action }
111
+ }.flatten
112
+
113
+ permission.bind_permission bind
114
+ display ? permission.display_on : permission.display_off unless display.nil?
115
+
116
+ # 执行自定义闭包
117
+ permission.instance_exec &block if block_given?
118
+
119
+ # 设置elements所属permission
120
+ permission.inject_elements_permission
121
+ permission.container = container
122
+
123
+ # 将该权限放入集合
124
+ set permission
125
+ end
126
+
127
+
128
+ class << self
129
+ def build_by_permissions permissions
130
+ return unless permissions.is_a? Array
131
+ new.tap { |p| p.append(*permissions) }
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,13 @@
1
+ module Fibman
2
+ class Railtie < Rails::Railtie
3
+ initializer "fibman.initialize_dsl" do
4
+ ActiveSupport.on_load(:action_controller) do
5
+ include Fibman::Additions::ControllerDslAddition
6
+ end
7
+
8
+ ActiveSupport.on_load(:active_record) do
9
+ include Fibman::Additions::TargeterDslAddition
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ module Fibman
2
+ class Trie
3
+ attr_accessor :key, :data, :subnode
4
+
5
+ def initialize key, data, subnode={}
6
+ @key = key
7
+ @data = data
8
+ @subnode = subnode
9
+ end
10
+
11
+ def dig *node_key
12
+ return nil unless node_key.is_a? Array
13
+
14
+ if node_key.size < 1
15
+ return data
16
+ end
17
+
18
+ current_key = node_key.first
19
+ node_key.shift
20
+
21
+ subnode.has_key?(current_key) ? subnode[current_key]&.dig(*node_key) : nil
22
+ end
23
+
24
+ def add_sub key, node
25
+ t = Trie.new key, node
26
+ subnode[key] = t
27
+ t
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ # 版本
2
+ module Fibman
3
+ VERSION = "2.0.0".freeze
4
+ end
data/lib/fibman.rb ADDED
@@ -0,0 +1,26 @@
1
+ require "forwardable"
2
+ require "active_support/all"
3
+
4
+ require "fibman/railtie" if defined? Rails
5
+
6
+ require "fibman/config"
7
+ require "fibman/container"
8
+ require "fibman/element"
9
+ require "fibman/element_package"
10
+ require "fibman/error"
11
+ require "fibman/fpa"
12
+ require "fibman/handle_sub"
13
+ require "fibman/permission"
14
+ require "fibman/permissions_collection"
15
+ require "fibman/trie"
16
+ require "fibman/version"
17
+
18
+ require "fibman/additions/container_addition"
19
+ require "fibman/additions/targeter_addition"
20
+ require "fibman/additions/rails_controller_addition"
21
+ require "fibman/additions/dsl_addition"
22
+
23
+ module Fibman
24
+ extend SingleForwardable
25
+ def_delegators Fibman::Container, :new, :ls
26
+ end
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fibman
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Warrenoo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: 多模块持久化权限管理系统
112
+ email:
113
+ - 541991a@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rubocop.yml"
120
+ - ".simplecov"
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - fibman.gemspec
125
+ - lib/fibman.rb
126
+ - lib/fibman/additions/container_addition.rb
127
+ - lib/fibman/additions/dsl_addition.rb
128
+ - lib/fibman/additions/rails_controller_addition.rb
129
+ - lib/fibman/additions/targeter_addition.rb
130
+ - lib/fibman/config.rb
131
+ - lib/fibman/container.rb
132
+ - lib/fibman/element.rb
133
+ - lib/fibman/element_package.rb
134
+ - lib/fibman/error.rb
135
+ - lib/fibman/fpa.rb
136
+ - lib/fibman/permission.rb
137
+ - lib/fibman/permissions_collection.rb
138
+ - lib/fibman/railtie.rb
139
+ - lib/fibman/trie.rb
140
+ - lib/fibman/version.rb
141
+ homepage: https://github.com/Warrenoo/fib
142
+ licenses:
143
+ - MIT
144
+ metadata: {}
145
+ post_install_message:
146
+ rdoc_options: []
147
+ require_paths:
148
+ - lib
149
+ required_ruby_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ requirements: []
160
+ rubyforge_project:
161
+ rubygems_version: 2.5.1
162
+ signing_key:
163
+ specification_version: 4
164
+ summary: 权限管理
165
+ test_files: []