shiro的配置主要分爲兩部分:權限(包括:帳戶、密碼、角色、資源),模塊(包括:認證、受權、session、cache、web)。在學習的過程當中千萬要分開理解,否則很容易混淆。在單獨使用shiro的時候,咱們須要配置xxx.ini文件來修改咱們須要的信息。shiro的每一個部分都是以[xxx]開始,其中[main]是模塊配置,後面的[users],[roles],[urls]則是權限關配置。java
[users] #提供了對用戶/密碼及其角色的配置,用戶名=密碼,角色1,角色2 username=password,role1,role2 [roles] #提供了角色及權限之間關係的配置,角色=權限1,權限2 role1=permission1,permission2
[users]:下面配置的是帳戶、密碼,以及該帳戶的權限。
mysql
[roles]:對應每個角色的訪問資源。
web
(shiro採起的是:一個用戶對應多個角色,一個角色對應多個資源)
redis
a)先看一下 配置 的代碼:這段代碼直接經過源碼實現來一步步new出來的。
sql
//全局sercurityManager DefaultSecurityManager securityManager = new DefaultSecurityManager(); //設置authenticator ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator(); authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy()); securityManager.setAuthenticator(authenticator); //設置authorizer ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer(); authorizer.setPermissionResolver(new WildcardPermissionResolver()); securityManager.setAuthorizer(authorizer); //設置Realm DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/shiro"); ds.setUsername("root"); ds.setPassword(""); JdbcRealm jdbcRealm = new JdbcRealm(); jdbcRealm.setDataSource(ds); jdbcRealm.setPermissionsLookupEnabled(true); securityManager.setRealms(Arrays.asList((Realm) jdbcRealm)); //將SecurityManager設置到SecurityUtils 方便全局使用 SecurityUtils.setSecurityManager(securityManager); //登陸 Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123"); subject.login(token); Assert.assertTrue(subject.isAuthenticated());
b)介紹:
數據庫
經過上面這段代碼你們能夠看見幾個主要的實現模塊:SecurityManager、Realm等等。這是經過new的方式來實現的,那咱們平時的配置又有什麼用呢?爲了將這些模塊組裝起來,而且作個一個高可用,低耦合、高擴展性的框架。shiro裏面採用了 IOC 的方式,經過JVM的功能實現的java 反射,來組裝實現低耦合、高可擴展性。在使用者本身開發的擴展中,經過實現shiro提供的接口完成本身的功能,而後經過配置文件替換默認的功能(shiro的源碼很經典,建議你們多讀讀)。
apache
c)主要模塊實現
緩存
一、用戶認證: 認證realm、AuthenticationStrategy(這個主要、針對多個realm)session
認證realm的實現:實現realm接口。這裏每個realm均可以看做是一個元數據查詢接口(能夠是數據庫、txt、redis)。
框架
實現realm: public class AuthenticationTest implements Realm { /** * @see 實現一個認證:每個realm都會和咱們維護的數據聯繫 */ // 認證 public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("myRealm"); String userName = (String) token.getPrincipal(); // 帳戶 String password = new String((char[]) token.getCredentials()); // 密碼 if (!"userName".equals(userName)) { throw new UnknownAccountException();// 帳戶錯誤 } if (!"password".equals(password)) { throw new IncorrectCredentialsException();// 密碼錯誤 } return new SimpleAuthenticationInfo(userName, password, getName()); } // 每一個realm都有一個名稱 public String getName() { return "myrealm"; } // 是否支持token public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; } } 配置:ini ##自定義realm全限名#### myRealm1=com.fxl.Test.LearnOne.shiro.authentication.AuthenticationTest ###注入##### securityManager.realms=$myRealm1
AuthenticationStrategy的類型:當有多個realm的時候,例若有多個數據元,咱們就須要知道哪個正確才能完成認證,也就是認證策略。官方提供了3種,知足咱們大部分須要。
FirstSuccessfulStrategy:只要有一個Realm驗證成功便可,只返回第一個Realm身份驗證成功的認證信息,其餘的忽略;
AtLeastOneSuccessfulStrategy:只要有一個Realm驗證成功便可,和FirstSuccessfulStrategy不一樣,返回全部Realm身份驗證成功的認證信息;(默認)
AllSuccessfulStrategy:全部Realm驗證成功纔算成功,且返回全部Realm身份驗證成功的認證信息,若是有一個失敗就失敗了。
修改成所用都成功: allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
二、受權:一個subject的權限獲取和每一次訪問的權限驗證,都會使用到authorization模塊。
一、默認實現: 默認的資源字符串:資源標識符:操做:對象實例 eg: 單資源單權限:user:update:5 表示的是:用戶:修改:角色5 單資源多權限:user:update,create:5 單資源全部權限:user:*:5 authorization的realm實現:繼承 authorizingRealm public class Authoriation extends AuthorizingRealm { /*** * @see 權限查詢 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) { SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo(); // 添加角色 sai.addRole("admim"); // 單角色 List<String> roles = new ArrayList<String>();// 多角色 roles.add("admin1"); roles.add("admin2"); sai.addRoles(roles); // 添加資源權限 sai.addStringPermission("user:update"); List<String> permissions = new ArrayList<String>();// 多角色 permissions.add("user:create"); permissions.add("user:delete"); sai.addStringPermissions(permissions); return sai; } /** * @see 認證查詢 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException { // TODO Auto-generated method stub return null; } } 配置ini: ############# authorization ################ myRealm2=com.fxl.Test.LearnOne.shiro.authorization.AuthoriationTest securityManager.realms=$myRealm2 二、自定義的資源字符串實現: 須要實現3個接口:permission,permissionResolver,rolePermissionResolver permission:定義了字符串的 組成方式 和 對比方式 permissionResolver:根據字符串的組成方式來實現不一樣的permission對象. rolePermissionResolver:經過不一樣的角色來獲取不一樣的permission對戲。 ps:每一permission都是一個對象實例,因此須要咱們實現permission接口,須要咱們經過組成方式實現perimission。 eg:permission1: +資源標識符+操做+對象ID permission2: -資源標識符+操做+對象ID 配置的文件(ini): #################自定義的 permission############ authorizer=org.apache.shiro.authz.ModularRealmAuthorizer #自定義permissionResolver permissionResolver=com.fxl.Test.LearnOne.shiro.authorization.MyRolePermissionReslover authorizer.permissionResolver=$permissionResolver #自定義rolePermissionResolver rolePermissionResolver=com.fxl.Test.LearnOne.shiro.authorization.MyPermissionReslover authorizer.rolePermissionResolver=$rolePermissionResolver securityManager.authorizer=$authorizer
三、realm:realm算是authencation和authorization模塊的一部分。單獨拿出來是由於咱們能夠經過實現直接繼承一個authorizingRealm來實現認證和受權。
public class RealmTest extends AuthorizingRealm { /*** * @see 權限查詢 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) { SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo(); // 添加角色 sai.addRole("admim"); // 單角色 List<String> roles = new ArrayList<String>();// 多角色 roles.add("admin1"); roles.add("admin2"); sai.addRoles(roles); // 添加資源權限 sai.addStringPermission("user:update"); List<String> permissions = new ArrayList<String>();// 多角色 permissions.add("user:create"); permissions.add("user:delete"); sai.addStringPermissions(permissions); return sai; } /** * @see 認證查詢 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("myRealm"); String userName = (String) token.getPrincipal(); // 帳戶 String password = new String((char[]) token.getCredentials()); // 密碼 if (!"userName".equals(userName)) { throw new UnknownAccountException();// 帳戶錯誤 } if (!"password".equals(password)) { throw new IncorrectCredentialsException();// 密碼錯誤 } return new SimpleAuthenticationInfo(userName, password, "myRealm"); } } 配置: ############# authorization ################ myRealm3=com.fxl.Test.LearnOne.shiro.authorization.RealmTest securityManager.realms=$myRealm2
三、cache:因爲每一次受權、session都會查詢一次元數據(例如:從數據庫中查詢受權字符串)。很影響性能,cache就是咱們的不二之選。shiro默認使用的EHchache,固然也能夠經過實現接口來實現
緩存主要用在realm查詢和session中: 一、擴展接口: cache:shiro不一樣模塊調用的通用接口。若是我須要本身實現cache,則須要將這些接口都換掉 CacheManager:獲取一個cache對象。實現這個接口,能夠從第三方接口中獲取cache。 CacheManagerAware:注入CacheManager,在authencation、authorization、sessionDAO中都有這個接口實現。而後經過IOC,注入咱們本身的cache。 二、默認cache:Ehcache 三、配置: realm:認證、受權 myRealm3=com.fxl.Test.LearnOne.shiro.authorization.RealmTest myRealm3.credentialsMatcher=$credentialsMatcher #######開啓cacheManager####### myRealm3.cachingEnabled=true myRealm3.authenticationCachingEnabled=true myRealm3.authenticationCacheName=authenticationCache myRealm3.authorizationCachingEnabled=true myRealm3.authorizationCacheName=authorizationCache securityManager.realms=$myRealm3 ##########設置cacheManager################ cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager cacheManager.cacheManagerConfigFile=classpath:shiro-ehcache.xml securityManager.cacheManager=$cacheManager; session配置cache: ##################開啓session的cacheManager################# sessionManager=org.apache.shiro.session.mgt.DefaultSessionManager securityManager.sessionManager=$sessionManager; #####################實現sessionDAO的cacheManager########### sessionDAO=com.fxl.Test.LearnOne.shiro.authorization.session.dao.MySessionDAO sessionDAO.activeSessionsCacheName=shiro-activeSessionCache;