fibman 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []