Security - 輕量級Java身份認證、訪問控制安全框架

前言java

  此框架由小菜獨立開發,而且已經在生產環境中運行大約一年時間。git

  也就是說,Security 框架寫出來有一段時間了,可是一直沒有公佈、開源,通過不斷迭代完善,終於算是拿得出手啦~github

  Security 框架存在的意義並非爲了替代 Shiro 或 Spring Security ,並且提供另外一種選擇。web

  當讀者由於現有安全框架的複雜繁瑣而苦惱時,爲何不嘗試一下 Security 呢?
redis

  請原諒小菜在本文直接照搬 GitHub 的 README,之後小菜會陸續完善使用教程和相關 Demo ,敬請關注~spring

  最後但願讀者能給出寶貴意見、及時反饋問題,來幫助小菜繼續完善框架。數據庫

README後端

簡介

  本框架基於Spring MVC開發,是一款輕量級的安全認證框架。緩存

  拋棄ShiroSpring Security等安全框架繁瑣的配置,改成註解實現權限管理,配合Spring MVCRequestMapping註解,完美實現細粒度的權限控制。安全

  本框架以Redis做爲持久化數據庫,Ehcache做爲內存級緩存,知足高性能需求。

  本框架刪繁就簡,以角色做爲權限認證的惟一標準,並不是傳統的RBAC權限模型,在這裏沒有權限的概念,只有角色,角色就是權限,權限就是角色,所以本框架適合應用於互聯網項目,尤爲適合先後端分離模式下的後端接口。

特性

  • 高性能(設計簡潔、內置緩存)
  • 基於註解
  • 安全的密碼加密機制
  • 靈活的配置項
  • 易於集成、擴展
  • Session共享
  • 分佈式部署
  • 實現匿名認證基礎的登錄認證基於角色的權限管理基於範圍表達式的權限管理HTTP Basic Authentication
  • 併發登陸控制
  • 基礎的在線會話管理
  • 驗證碼框架封裝
  • 第三方登陸集成

主要依賴

  • Spring MVC,基礎依賴
  • Httpclient,第三方登錄依賴
  • FastJson,序列化依賴
  • Ehcache,緩存依賴
  • Redis,持久化依賴

集成

添加Maven項目依賴

<!-- security frame work -->
<dependency>
    <groupId>org.yangyuan</groupId>
    <artifactId>security</artifactId>
    <version>0.0.1</version>
</dependency>

與Spring MVC集成

<!-- 掃描spring註解 -->
<context:component-scan base-package="com.yourself, org.yangyuan.security" />
<!-- 身份認證攔截器 -->
<mvc:interceptors>
    <bean class="org.yangyuan.security.servlet.SecurityInterceptor"></bean>
</mvc:interceptors>

添加配置文件

  將本項目中的security.properties文件拷貝到真實項目resources根目錄下,與log4j.properties位置相同,即保證編譯後這個文件在classes目錄下。

security.properties說明

#Session有效期
#這是一個相對值,相對於用戶最後一次訪問的時間
#也就是說,只有當用戶超過此時間不活躍,Session纔會失效
#單位秒(s)
session.expiresMilliseconds=2592000000
#是否啓用Session垃圾回收器
session.gc.open=true
#Session垃圾回收器Lua腳本
session.gc.script=for i=48,83,1 do     local partition     if(i > 57) then         partition = string.char(i + 39)     else         partition = string.char(i)     end          local setkey = 'security:session:set:'..partition     local principals = redis.call('ZRANGEBYSCORE', setkey, '-inf', ARGV[1])     redis.call('ZREMRANGEBYSCORE', setkey, '-inf', ARGV[1])     if(principals and (table.maxn(principals) > 0)) then         for ii,vv in ipairs(principals) do             local hashkey = 'security:session:hash:'..partition             redis.call('HDEL', hashkey, vv)         end     end end
#Session垃圾回收器執行時間間隔
#單位秒(s)
session.gc.gcDelaySecond=86400



#cookie名稱
cookie.name=sid
#cookie域名
cookie.domain=.cospace.xyz
#cookie路徑
cookie.path=/
#此配置爲true時,cookie沒法經過js腳本操做
cookie.http_only=true
#是否啓用HTTPS
cookie.secure=true
#cookie有效期,通常不須要改動,目前設置的是最大值,至關於永不過時
#由於cookie的生命週期由服務器端維護,因此客戶端不須要關心過時時間
cookie.max_age=315360000



#Redis客戶端鏈接工廠
#負責提供Redis客戶端鏈接
common.redisResourceFactory=cc.cospace.web.security.dao.DefaultRedisResourceFactory



#安全管理器實現
core.securityManager=org.yangyuan.security.core.DefaultSecurityManager
#安全惟一標識生成器實現
core.principalFactory=org.yangyuan.security.core.DefaultPrincipalFactory
#緩存管理器實現
core.cacheManager=org.yangyuan.security.core.DefaultCacheManager
#是否複用客戶端subject
#若是設爲true,客戶端登錄時若是攜帶有subject信息,那麼複用此subject,再也不建立新的subject
#若是設爲false,則登陸時忽略客戶端攜帶的subject信息,老是建立新的subject
core.useClientSubjectLogin=false
#併發主題控制器
#[org.yangyuan.security.core.MultiportConcurrentSubjectControl]容許同一個帳號同時在不一樣客戶端登錄
#[org.yangyuan.security.core.SingleConcurrentSubjectControl]同一個帳號同一時刻只能在一個客戶端登錄,若是以前在其餘客戶端登錄過,那麼以前的登錄將失效
#[org.yangyuan.security.core.RefuseConcurrentSubjectControl]同一個帳號同一時刻只能在一個客戶端登錄,若是以前在其餘客戶端登錄過,那麼本次登錄將會失敗,除非其餘客戶端主動退出登錄
core.concurrentSubjectControl=org.yangyuan.security.core.MultiportConcurrentSubjectControl
#認證回調
#此處理器用來響應認證結果(成功、失敗、拒絕訪問)
#具體的響應依賴於具體的業務,框架只負責通知認證結果
core.securityAuthHandler=cc.cospace.web.security.core.DefaultSecurityAuthHandler



#ehcache緩存數據訪問層(緩存層)
dao.ehcacheSessionDao=org.yangyuan.security.dao.EhcacheSessionDao
#redis數據訪問層(持久化層)
dao.redisSessionDao=org.yangyuan.security.dao.RedisSessionDao
#持久化數據源(用戶名密碼模式)
dao.jdbcRealm=org.yangyuan.security.realm.jdbc.JdbcRealm
#第三方數據源
dao.remoteRealm=org.yangyuan.security.realm.remote.RemoteRealm
#本地認證數據訪問層(用戶名密碼模式)
dao.jdbcSessionDao=org.yangyuan.security.dao.JdbcSessionDao
#第三方登陸認證數據訪問層
dao.remoteSessionDao=org.yangyuan.security.dao.RemoteSessionDao
#用戶名密碼模式登陸適配器
#此適配器實現安全認證與具體項目用戶數據存儲之間的解耦
dao.jdbcRealmAdaptor=userService
#第三方登陸適配器
#此適配器實現安全認證與具體項目用戶數據存儲之間的解耦
dao.remoteRealmAdaptor=userService



#cache在內存中最多能夠存放的元素的數量。
#0表示沒有限制。
#若是放入cache中的元素超過這個數值,有兩種可能:
#一、若overflowToDisk的屬性值爲true,會將cache中多出的元素放入磁盤文件中。
#二、若overflowToDisk的屬性值爲false,會根據memoryStoreEvictionPolicy的策略替換cache中原有的元素。
cache.maxElementsInMemory=10000
#緩存是否永駐內存。
#若是值是true,cache中的元素將一直保存在內存中,不會由於時間超時而丟失。
#所以在這個值爲true的時候,timeToIdleSeconds和timeToLiveSeconds兩個屬性的值就不起做用了。
cache.eternal=false
#內存中的元素數量溢出是否寫入磁盤。
#系統會根據標籤<diskStore path="java.io.tmpdir"/>中path的值查找對應的屬性值。
#若是系統的java.io.tmpdir的值是/temp,寫入磁盤的文件就會放在這個文件夾下,文件的名稱是cache的名稱,後綴名爲data。
cache.overflowToDisk=false
#是否持久化內存中的緩存到磁盤。
#當這個屬性的值爲true時,系統在初始化的時候會在磁盤中查找文件名爲cache名稱,後綴名爲index的的文件,如CACHE_FUNC.index。
#這個文件中存放了已經持久化在磁盤中的cache的index,找到後把cache加載到內存。
cache.diskPersistent=false
#訪問cache中元素的最大間隔時間。
#若是超過此時間cache中的某個元素沒有任何訪問,那麼這個元素將被從cache中清除。
cache.timeToIdleSeconds=900
#cache中元素的總生存時間,cache中的某個元素從建立到消亡的時間。
#從建立開始計時,當超過這個時間,這個元素將被從cache中清除,即使是這個元素被頻繁訪問。
cache.timeToLiveSeconds=7200
#內存存儲與釋放清理策略
#LRU最近最少使用
#LFU歷史訪問頻率最低
#FIFO先進先出
cache.memoryStoreEvictionPolicy=LRU



#普通驗證碼有效期
#單位s
captcha.normal.expireSecond=900
#普通驗證碼屢次發送最短期間隔
#單位s
captcha.normal.minIntervalSecond=50
#圖形驗證碼有效期
#單位s
captcha.image.expireSecond=600
#圖形驗證碼錯誤統計週期
#單位s
captcha.image.wrongPeriodSecond=60
#圖形驗證碼統計週期內容許最大錯誤次數
captcha.image.periodMaxWrongCount=3

具體業務類實現

  • common.redisResourceFactory,爲框架提供Redis鏈接,實現RedisResourceFactory接口。
  • core.securityAuthHandler,自定義認證結果行爲,用來處理認證成功、未登陸、權限不足的具體業務,實現SecurityAuthHandler接口。
  • dao.jdbcRealmAdaptor,提供用戶名/密碼登錄模式必要的數據,具體出參入參參考源碼註釋,實現JdbcRealmAdaptor接口。
  • dao.remoteRealmAdaptor,提供第三方登錄模式必要的數據,具體出參入參參考源碼註釋,實現RemoteRealmAdaptor接口。

  security.properties文件中配置的全部類型,能夠配置成完整類名(包名+類名),也能夠配置成spring IOC中的Bean名稱,根據業務狀況自由選擇。

  通常來說,除非須要本身擴展框架,不然只須要實現具體業務類,而後修改一下cookie相關配置便可,其餘配置項都可使用默認配置。

驗證碼模塊使用介紹

  驗證碼模塊只實現了公共邏輯,並無實現具體的發送邏輯,目的是留給使用者更多的操做空間,使得框架具備更強的適應性。

  若是須要使用驗證碼模塊,最佳實踐以下:

  • 若是須要使用手機短信郵箱郵件驗證碼,則定義一個抽象類,假設名稱爲AbstractPhoneEmailSecurityCaptchaService,繼承模塊中的AbstractPhoneEmailSecurityCaptcha,實現newCodesendToPhonesendToEmail方法,這三個方法是公共方法,但必須交給使用者實現,由於不一樣的項目發送短信、郵件的方式不盡相同,生成驗證碼的規則也不盡相同。而後在項目中以AbstractPhoneEmailSecurityCaptchaService爲基礎,派生出具體的業務類,好比發送註冊驗證碼的業務類RegisterCaptchaService,繼承AbstractPhoneEmailSecurityCaptchaService,而後實現nametitlecontent方法便可。
  • 若是須要使用圖形驗證碼,則定義一個抽象類,假設名稱爲AbstractSecurityImageCaptchaService,繼承模塊中的AbstractSecurityImageCaptcha,實現newCode方法,生成的驗證碼取決於實際項目中圖形生成器的能力,避免生成沒法被圖形生成器識別的字符,固然,圖形生成器您本身實現,看着辦。而後在項目中以AbstractSecurityImageCaptchaService爲基礎,派生出具體的業務類,好比登錄圖形驗證碼的業務類LoginImageCaptchaService,繼承AbstractSecurityImageCaptchaService,而後實現name方法便可。

  經過以上描述能夠看出,驗證碼模塊只是封裝了繁瑣的驗證碼發送標記、驗證等操做,並不干預具體的發送實現。

  使用者封裝好適合本身的抽象基類後,不論任何業務,只須要繼承抽象基類便可輕鬆實現,並自然實現業務之間的隔離。

  總結一下,使用者只須要關注發送手機短信發送郵件生成驗證碼文本生成驗證碼圖片具體實現,而後根據具體業務設定好驗證碼標題驗證碼內容業務名稱(用來隔離業務)便可。

使用

  通過前期配置以後,使用就很是簡單了!

  只須要在Controller層使用Security註解便可,Security註解具體使用方法請參考源碼註釋。

  本框架只關注角色認證,而不關注角色的存儲、定義,完全實現安全認證框架與實際項目之間的解耦。

  在定義角色名稱時,不該該出現框架已經佔用的關鍵字,包括:[]{}><,:,不然會引發衝突。

GitHub 項目地址

Security

相關文章
相關標籤/搜索