(1)测试类web
// 用户登录和退出,这里我自定了一个realm(开发确定须要自定义realm获取数据库密码和权限) @Test public void testCustomRealmMd5() { // 建立securityManager工厂,经过ini配置文件建立securityManager工厂 Factory<SecurityManager> factory = new IniSecurityManagerFactory( "classpath:shiro-realm-md5.ini"); // 建立SecurityManager SecurityManager securityManager = factory.getInstance(); // 将securityManager设置当前的运行环境中 SecurityUtils.setSecurityManager(securityManager); // 从SecurityUtils里边建立一个subject Subject subject = SecurityUtils.getSubject(); // 在认证提交前准备token(令牌) // 这里的帐号和密码 未来是由用户输入进去 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "111111"); try { // 执行认证提交 subject.login(token); } catch (AuthenticationException e) { e.printStackTrace(); } // 是否定证经过 boolean isAuthenticated = subject.isAuthenticated(); System.out.println("加密后是否定证经过:" + isAuthenticated); // 退出操做 subject.logout(); // 是否定证经过 isAuthenticated = subject.isAuthenticated(); System.out.println("退出后是否定证经过:" + isAuthenticated); }
(2)shiro-realm-md5.ini (有关散列加密下面会举例子)算法
我在ini配置了加密的规则,这个规则要和用户注册保存的密码加密规则一致。spring
[main] #定义凭证匹配器 credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher #散列算法 credentialsMatcher.hashAlgorithmName=md5 #散列次数 credentialsMatcher.hashIterations=1 #将凭证匹配器设置到realm customRealm=com.jincou.shiro.realm.CustomRealmMd5 customRealm.credentialsMatcher=$credentialsMatcher securityManager.realms=$customRealm
(3)自定义CustomRealmMd5类数据库
/** *自定义Realm特色 *(1)继承AuthorizingRealm类 *(2)重写AuthenticationInfo(认证) * doGetAuthorizationInfo(受权)两个方法 * 注意: * 1:这里password = "f3694f162729b7d0254c6e40260bf15c"确定也是经过明文(这里指zhangsan)+盐(这里是qwerty)进行加密后的字符串 * 2:实际应用是将盐和散列后的值存在数据库中,自动realm从数据库取出盐和加密后的值由shiro完成密码校验。 * 3:这里要注意它们两的加密规则必定要一致,不然没法比较。 */ public class CustomRealmMd5 extends AuthorizingRealm { // 设置realm的名称(任意和其它也无关联) @Override public void setName(String name) { super.setName("customRealmMd5"); } // 用于认证 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { System.out.println("测试..自定义CustomRealmMd5方法里面......"); // token是用户输入的 // 第一步从token中取出身份信息 String userCode = (String) token.getPrincipal(); // 第二步:根据用户输入的userCode从数据库查询 // .... //若是数据库查询不到zhangsan用户信息,则返回null /*if(user==null){ return null; }*/ // 模拟从数据库查询到密码,散列值 String password = "f3694f162729b7d0254c6e40260bf15c"; // 从数据库获取salt String salt = "qwerty"; //上边散列值和盐对应的明文:111111 // 若是查询到返回认证信息AuthenticationInfo,这里的密码加密判断交给底层处理 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( userCode, password, ByteSource.Util.bytes(salt), this.getName()); return simpleAuthenticationInfo; } // 用于受权(后面写) @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { return null; } }
运行效果:apache
结论:subject.login(token)我在提交认证,它就会去调用我自定义的CustomRealm,由于我在ini进行配置自定义CustomRealm编程
由于在ini里面配置的加密规则,那我第一次用户注册的时候,确定也须要按它的规则进行加密后,把密码保存到数据库ide
/** * 加密算法 */ public class MD5Test { public static void main(String[] args) { //原始 密码 String source = "111111"; //盐 String salt = "qwerty"; //散列次数(和ini中credentialsMatcher.hashIterations=1一致) int hashIterations = 1; //上边散列1次:f3694f162729b7d0254c6e40260bf15c //上边散列2次:36f2dfa24d0a9fa97276abbe13e596fc //第一个参数:散列算法 //这里的散列算法是md5要和ini中credentialsMatcher.hashAlgorithmName=md5一致) //第二个参数:明文,原始密码 //第三个参数:盐,经过使用随机数 //第四个参数:散列的次数,好比散列两次,至关 于md5(md5('')) SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations); System.out.println(simpleHash.toString()); } } //这个结果:f3694f162729b7d0254c6e40260bf15c就是在自定义realm中的密文也就是该用户保存到数据库中的密文。
Shiro 支持三种方式的受权:
(1)编程式:经过写if/else 受权代码块完成:测试
Subject subject = SecurityUtils.getSubject(); if(subject.hasRole(“admin”)) { //有权限 } else { //无权限 }
(2)注解式:经过在执行的Java方法上放置相应的注解完成ui
@RequiresRoles("admin") public void hello() { //有权限 }
(3)JSP/GSP 标签:在JSP/GSP 页面经过相应的标签完成this
<shiro:hasRole name="admin"> <!— 有权限—> </shiro:hasRole>
这里受权测试使用第一种编程方式,实际与web系统集成使用后两种方式。
(1)测试类
// 自定义realm进行资源受权测试 @Test public void testAuthorizationCustomRealm() { // 建立SecurityManager工厂 Factory<SecurityManager> factory = new IniSecurityManagerFactory( "classpath:shiro-realm.ini"); // 建立SecurityManager SecurityManager securityManager = factory.getInstance(); // 将SecurityManager设置到系统运行环境,和spring后将SecurityManager配置spring容器中,通常单例管理 SecurityUtils.setSecurityManager(securityManager); // 建立subject Subject subject = SecurityUtils.getSubject(); // 建立token令牌 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "111111"); // 执行认证 try { subject.login(token); } catch (AuthenticationException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("认证状态:" + subject.isAuthenticated()); // 认证经过后执行受权 // 基于资源的受权,调用isPermitted方法会调用CustomRealm从数据库查询正确权限数据 // isPermitted传入权限标识符,判断user:create:1是否在CustomRealm查询到权限数据以内 boolean isPermitted = subject.isPermitted("user:create:1"); System.out.println("单个权限判断" + isPermitted); boolean isPermittedAll = subject.isPermittedAll("user:create:1", "user:create"); System.out.println("多个权限判断" + isPermittedAll); // 使用check方法进行受权,若是受权不经过会抛出异常 subject.checkPermission("items:add:1"); }
(2)shiro-realm.ini
[main] #自定义 realm customRealm=com.jincou.shiro.realm.CustomRealm #将realm设置到securityManager securityManager.realms=$customRealm
(3)自定义CustomRealm类
public class CustomRealm extends AuthorizingRealm { // 用于认证(上面写过) @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { return null; } // 用于受权 @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { //从 principals获取主身份信息 //将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证经过填充到SimpleAuthenticationInfo中身份类型), String userCode = (String) principals.getPrimaryPrincipal(); //根据身份信息获取权限信息 //链接数据库... //模拟从数据库获取到数据 List<String> permissions = new ArrayList<String>(); permissions.add("user:create");//用户的建立 permissions.add("items:add");//商品添加权限 //.... //查到权限数据,返回受权信息(要包括 上边的permissions) SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //将上边查询到受权信息填充到simpleAuthorizationInfo对象中 simpleAuthorizationInfo.addStringPermissions(permissions); return simpleAuthorizationInfo; } }
运行结果:
想太多,作太少,中间的落差就是烦恼。想没有烦恼,要么别想,要么多作。少校【5】