<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency>
[users] test=123456 lisi=123456
public class TestShiro { public static void main(String[] args) { //獲取安全管理器工廠 IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro.ini"); //獲取安全管理器 SecurityManager securityManager = iniSecurityManagerFactory.getInstance(); //set認證器 SecurityUtils.setSecurityManager(securityManager); //subject發起認證,獲取subject Subject subject = SecurityUtils.getSubject(); AuthenticationToken authenticationToken = new UsernamePasswordToken("test","123456"); //認證失敗會拋出異常 密碼:CredentialsException 帳戶:UnknownAccountException try { subject.login(authenticationToken); } catch (AuthenticationException e) { e.printStackTrace(); } //當前subject是否定證經過 boolean authenticated = subject.isAuthenticated(); System.out.println(authenticated); } }
token攜帶身份和憑證信息--->subject發起認證--->SimpleAccountRealm(doGetAuthenticationInfo)獲取配置文件中的用戶信息---->CredentialsMatcher接口的實現類SimpleCredentialsMatcher:doCredentialsMatch方法對配置文件中的信息與token攜帶的信息進行比對--->認證成功或者失敗。java
AuthenticatingRealm //抽象類 //3.關鍵屬性 該屬性爲憑證匹配器 CredentialsMatcher credentialsMatcher; //1.該方法爲抽象方法 其做用使用來獲取數據 protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException;
SimpleAccountRealm //2.實現了AuthenticatingRealm抽象方法,用來獲取配置文件中的用戶信息,該類不作數據比對
SimpleCredentialsMatcher //4.shiro中默認的憑證匹配器 public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { Object tokenCredentials = this.getCredentials(token); Object accountCredentials = this.getCredentials(info); return this.equals(tokenCredentials, accountCredentials); }
如下代碼或者截圖貼出最重要的地方.sql
類繼承關係
數據庫
AuthenticatingRealm類apache
abstract class AuthenticatingRealm{ //憑證匹配器 接口,其實現類作數據比對 private CredentialsMatcher credentialsMatcher; //獲取配置文件中的用戶信息 protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException; }
該抽象方法返回類型AuthenticationInfo接口:api
AuthorizingRealm類 抽象方法後面測試受權時使用安全
abstract class AuthorizingRealm{ // //該抽象方法 獲取數據 獲取受權的數據 protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1); }
該抽象方法返回類型AuthorizationInfo接口:
app
CredentialsMatcher憑證匹配器接口:框架
其中:SimpleCredentialsMatcher是shiro中默認的憑證匹配器,其子類Hashxxx等都是作加密認證時使用
ide
public class MyRealm extends AuthenticatingRealm { //實現抽象方法doGetAuthenticationInfo @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String principal =(String) authenticationToken.getPrincipal(); //查庫取回User對象 SqlSession sqlSession = null; try { sqlSession = MySqlSession.getSqlSession(); } catch (IOException e) { e.printStackTrace(); } UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserByUserName(principal); AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal,user.getPassword(),this.getName()); return authenticationInfo; } }
[main] #自定義 realm customRealm=com.nyist.test.MyRealm #將realm設置到securityManager securityManager.realms=$customRealm
注意:須要導入一個jar測試
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
public class TestMD5 { public static void main(String[] args) { Md5Hash hash = new Md5Hash("123456","salt",1024); String s = hash.toHex(); System.out.println(s); //a18d2133f593d7b0e3ed488560404083 } }
[main] #自定義憑證匹配器 hashedCredentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher #憑證匹配器通知AuthenticatingRealm,因爲自定義realm繼承了AuthenticatingRealm,直接設置已有的MyRealm屬性便可 #自定義 realm customRealm=com.nyist.test.MyRealm customRealm.credentialsMatcher=$hashedCredentialsMatcher hashedCredentialsMatcher.hashAlgorithmName=MD5 hashedCredentialsMatcher.hashIterations=1024 #將realm設置到securityManager .realms使用set方式賦值 securityManager.realms=$customRealm
坑:Caused by: java.lang.IllegalStateException: Required 'hashAlgorithmName' property has not been set. This is required to execute the hashing algorithm.
HashedCredentialsMatcher類中set方法很是規,set方法爲:setHashAlgorithmName
AuthenticationInfo doGetAuthenticationInfo()來自於AuthenticatingRealm類,獲取認證數據
AuthorizationInfo doGetAuthorizationInfo()來自於AuthorizingRealm類,獲取受權數據
public class MyRealm extends AuthorizingRealm { @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String principal =(String) authenticationToken.getPrincipal(); //userDao.queryUserByUserName SqlSession sqlSession = null; try { sqlSession = MySqlSession.getSqlSession(); } catch (IOException e) { e.printStackTrace(); } UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserByUserName(principal); /* * ByteSource.Util.bytes("salt") 鹽字段來自數據庫,憑證匹配器不能寫死鹽值 * 安全管理器能夠獲取到AuthenticationInfo中的鹽值 對用戶界面的憑證加密 * */ AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal,user.getPassword(),ByteSource.Util.bytes("salt"),this.getName()); return authenticationInfo; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //獲取身份信息 Principal用戶名、手機號、郵箱地址等 一個主體能夠有多個身份,可是必須有一個主身份(Primary Principal) String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal(); /* * 用戶----角色----權限 * 中間表 中間表 * */ //由primaryPrincipal查庫--->得到角色info ---->獲取權限info SqlSession sqlSession = null; try { sqlSession = MySqlSession.getSqlSession(); } catch (IOException e) { e.printStackTrace(); } UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserByUserName(primaryPrincipal); //測試基於角色的受權 /*if (primaryPrincipal.equals(user.getUsername())){ // class SimpleAuthorizationInfo implements AuthorizationInfo SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.addRole("super"); return authorizationInfo; }*/ //測試基於資源的受權 if(primaryPrincipal.equals(user.getUsername())){ SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.addStringPermission("user:delete"); authorizationInfo.addStringPermissions(Arrays.asList("admin:delete","admin:add")); return authorizationInfo; } return null; } }
基於角色
//判斷當前主體是否包含此角色 boolean b = subject.hasRole("super"); List<String> list = Arrays.asList("super", "admin"); //判斷當前主體是否包含某個角色 boolean[] booleans = subject.hasRoles(list); //判斷當前主體是否包含所有的角色 boolean b = subject.hasAllRoles(list);
基於資源
boolean b = subject.isPermitted("admin:delete"); String[] strs={"admin:delete", "admin:add"}; boolean[] permitted = subject.isPermitted(strs); boolean permittedAll = subject.isPermittedAll(strs);
權限字符串的規則是:「資源標識符:操做:資源實例標識符」,意思是對哪一個資源的哪一個實例具備什麼操做,「:」是資源/操做/實例的分割符,權限字符串也可使用*通配符。
例子: