| 编辑推荐: | 
                                   
                                   
                                    文章主要介绍一个安全框架Shiro,并且详细介绍了Shiro架构图、环境搭建、认证实现以及密码加密实现方案等相关内容,希望对您能有所帮助。 
                                      本文来自于cnblogs,由火龙果软件Luca编辑、推荐。  | 
                                   
                                  | 
                             
                           
                          
                           一、Shiro简介 
                           Apache Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能。 
                           对于任何一个应用程序,Shiro都可以提供全面的安全管理服务。其不仅可以用在JavaSE环境,也可以用在JavaEE环境。 
                          二、Shiro架构图 
                           1.从外部来看Shiro,即从应用程序角度来观察如何使用Shiro完成工作。如下图: 
                            
                          2.从Shiro内部看Shiro的架构,如下图所示: 
                            
                          Subject(org.apache.shiro.subject.Subject)当前与软 件进行交互的实体(用户,第三方服务,cron 
                            job,等 等)的安全特定“视图” 
                          
                           SecurityManager:SecurityManager 是 
                            Shiro 架构的心脏。它基本上是一个“保护伞”对象,协调其管理的组件以确保它们能够一起顺利的工作类似于SpringMVC中的入口 
                            servlet 
                          
                            Realms:域 Realms 在 Shiro 和你的应用程序的安全数据之间担当 “桥梁”或“连接器”。当它实际上与安全相关的数据如用 
                            来执行身份验证(登录)及授权(访问控制)的用户帐户交互时, Shiro从一个或多个为应用程序配置的Real中寻找许多这样的东西 
                          
                           
                          Shiro 的环境搭建 
                          使用 shiro 实现登陆的操作 
                          第一步 导包 
                            第二步:书写 shiro.ini 文件 
                          
                           
                          第三步:书写测试代码 
                          
                             
                              |   import org.apache.shiro.SecurityUtils; 
                                  import org.apache.shiro.authc.UsernamePasswordToken; 
                                  import org.apache.shiro.config.IniSecurityManagerFact 
                                  ory; import org.apache.shiro.subject.Subject; 
                                  import org.apache.shiro.util.Factory; import 
                                  org.apache.shiro.mgt.SecurityManager; 
                                  public class TestA { 
                                  public static void main(String[] args) { 
                                  //[1]解析shiro.ini文件 
                                  Factory<SecurityManager> factory =new 
                                  IniSecurityManagerFactory("classpath:shiro.ini 
                                  "); 
                                  //[2]通过SecurityManager工厂获得 SecurityManager实例 
                                  SecurityManager securityManager = factory.getInstance(); 
                                  //[3]把SecurityManager对象设置到运行环境中 
                                  SecurityUtils.setSecurityManager(securityManag 
                                  er); 
                                  //[4]通过SecurityUtils获得主体subject Subject subject 
                                  = SecurityUtils.getSubject(); 
                                  //[5]书写自己输入的账号和密码---相当于用户自 己输入的账号和密码  
                                //我们拿着自己书写用户名密码去和shiro.ini 文 件中的账号密码比较 UsernamePasswordToken 
                                  token =new UsernamePasswordToken("sxt","root"); 
                                  //[6]进行身份的验证 subject.login(token); 
                                  //[7]通过方法判断是否登录成功 
                                  if(subject.isAuthenticated()){ System.out.println("登录成功"); 
                                  }else { System.out.println("登录失败"); 
                                  } 
                                  } 
                                  }  | 
                             
                           
                          
                           
                          Shiro 验证时异常分析 
                          DisabledAccountException 
                          账户失效异常 
                          
                            ConcurrentAccessException 
                          竞争次数过多 
                          
                            ExcessiveAttemptsException 
                          尝试次数过多 
                          
                            UnknownAccountException 
                          用户名不正确 
                          
                            IncorrectCredentialsException 
                          凭证(密码)不正确 
                          
                            ExpiredCredentialsException 
                            凭证过期 
                            
                          Shiro--认证流程 
                           
 
                           
                            
                           三、Shiro涉及常见名词 
                            
                          
                            四、Shiro配置文件详解 
                           shiro.ini文件放在classpath下,shiro会自动查找。其中格式是key/value键值对配置。INI配置文件一般适用于用户少且不需要在运行时动态创建的情景下使用。 
                          
                            ini文件中主要配置有四大类:main,users,roles,urls 
                            示例: 
                            
                            
                          1、[main] 
                            main主要配置shiro的一些对象,例如securityauthenticator,authcStrategy 
                            等等,例如: 
                            
                          2、[users] 
                            [users]允许你配置一组静态的用户,包含用户名,密码,角色,一个用户 
                            可以有多个角色,可以配置多个角色,例如: 
                            
						 
                          3、[roles] 
                            [roles]将角色和权限关联起来,格式为:角色名=权限字符串1,权限字符 
                            串2…..,例如: 
                           
                            
                          4、[urls] 
                          这部分配置主要在web应用中,格式为:url=拦截器[参数],拦截器[参数]……,例如 
                            
                          五、认证实现 
                            认证:验证用户是否合法 
                            在 shiro 中,用户需要提供principals (身份)和credentials(凭证) 
                            给shiro,从而实现对用户身份的验证。 
                          
                            5.1.principals(用户名) 
                            身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。 
                            例如:用户名/邮箱/手机号等。 
                          
                            5.2.credentials(密码) 
                            凭证,即只有主体知道的安全值,如密码/数字证书等。 
                          最常见的principals和credentials组合就是用户名/密码了。 
                          5.3 实现步骤 
                          5.3.1 导入jar包 
                            5.3.2 从源码的示例项目quickstart中拷贝shiro.ini放到src下,并配置 
                            5.3.3 编写代码 
                          
                           
                               package com.bjsxt.test;
                                 import org.apache.shiro.SecurityUtils; 
                                  import org.apache.shiro.authc.UsernamePasswordToken; 
                                  import org.apache.shiro.config.IniSecurityManagerFactory; 
                                  import org.apache.shiro.mgt.SecurityManager; 
                                  import org.apache.shiro.subject.Subject; 
                                  import org.junit.Test; 
                                 //实现简单认证 
                                  public class AuthenticationTest { 
                                  @Test 
                                  public void testAuthentication(){ 
                                  //1.构建SecurityManager工厂 
                                  IniSecurityManagerFactory securityManagerFactory 
                                  = new IniSecurityManagerFactory("classpath:shiro.ini"); 
                                  //2.通过securityManagerFactory工厂获取SecurityManager实例 
                                  SecurityManager securityManager = securityManagerFactory.getInstance(); 
                                  //3.将securityManager设置到运行环境当中 
                                  SecurityUtils.setSecurityManager(securityManager); 
                                  //4.获取subject实例 
                                  Subject subject = SecurityUtils.getSubject(); 
                                  //5.创建用户名密码验证令牌Token 
                                UsernamePasswordToken token = new UsernamePasswordToken 
                                ("victor","123456"); 
                                  //6.进行身份验证 
                                  subject.login(token); 
                                  //7.判断是否认证通过 
                                  System.out.println(subject.isAuthenticated()); 
                                  } 
                                  } | 
                           
                         
                            shiro.ini 
                          
                           
                          六、JDBCRealm 
                            Shiro默认使用自带的IniRealm,IniRealm从ini配置文件中读取用户的信息。 
                          
                            大部分情况下需要从系统的数据库中读取用户信息,所以需要使用JDBCRealm或自定义Realm。 
                          需求:使用JDBCRealm提供数据源,从而实现认证 
                          
                            实现步骤: 
                            6.1建users表(表名、字段对应上) 
                            6.2添加jar包(数据库驱动、数据库连接池、beanutils等) 
                            6.3编写shiro.ini 
                            6.4编写测试代码 
                            
                          AuthenticationTest.java 
                          
                             
                              package com.bjsxt.test; 
                                 
                                import org.apache.shiro.SecurityUtils; 
                                  import org.apache.shiro.authc.UsernamePasswordToken; 
                                  import org.apache.shiro.config.IniSecurityManagerFactory; 
                                  import org.apache.shiro.mgt.SecurityManager; 
                                  import org.apache.shiro.subject.Subject; 
                                  import org.junit.Test;
								      //实现简单认证 
                                  public class AuthenticationTest { 
                                  @Test 
                                  public void testAuthentication(){ 
                                  //1.构建SecurityManager工厂 
                                  IniSecurityManagerFactory securityManagerFactory 
                                  = new IniSecurityManagerFactory("classpath:shiro.ini"); 
                                  //2.通过securityManagerFactory工厂获取SecurityManager实例 
                                  SecurityManager securityManager = securityManagerFactory.getInstance(); 
                                  //3.将securityManager设置到运行环境当中 
                                  SecurityUtils.setSecurityManager(securityManager); 
                                  //4.获取subject实例 
                                  Subject subject = SecurityUtils.getSubject(); 
                                  //5.创建用户名密码验证令牌Token 
                                UsernamePasswordToken token = new UsernamePasswordToken 
                                ("victor","123456"); 
                                  //6.进行身份验证 
                                  subject.login(token); 
                                  //7.判断是否认证通过 
                                  System.out.println(subject.isAuthenticated()); 
                                  } 
                                  } | 
                           
                         
                            shiro.ini 
                          
                           
                               [main] 
                                #配置Realm 
                                jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
                                    #配置数据源 
                                  dataSource = com.mchange.v2.c3p0.ComboPooledDataSource 
                                  dataSource.driverClass = com.mysql.jdbc.Driver 
                                  dataSource.jdbcUrl = jdbc:mysql:///test 
                                  dataSource.user = root 
                                  dataSource.password = victor  
                                  jdbcRealm.dataSource = $dataSource  
                                 #将Realm注入给SecurityManager 
                                  securityManager.realm = $jdbcRealm | 
                           
                         
                           
                            
                          认证策略 
                          规定了如果有多个数据源的时候应该如何操作 
                          
                            AtLeastOneSuccessfulStrategy 
                          如果一个(或更多)Realm 验证成功,则整体的尝试被认为是成功的。 
                            如果没有一个验证成功, 
                            则整体尝试失败 类似于 java 中的 & 
                          
                            FirstSuccessfulStrategy 
                            只有第一个成功地验证的 Realm 返回的信息将被使用。所有进一步的 
                            Realm 将被忽略。如果没有一个验证成功,则整体尝试失败。 
                            类似于 java 中的 && 
                          
                            AllSucessfulStrategy 
                          为了整体的尝试成功,所有配置的 Realm 必须验证成功。如果没有一个验 
                            证成功,则整体尝试失败 
                         
                             
                              package com.bjsxt.shiro1; 
                                   import org.apache.shiro.SecurityUtils; 
                                  import org.apache.shiro.authc.IncorrectCredentialsException; 
                                  import org.apache.shiro.authc.UnknownAccountException; 
                                  import org.apache.shiro.authc.UsernamePasswordToken; 
                                  import org.apache.shiro.config.IniSecurityManagerFactory; 
                                  import org.apache.shiro.mgt.SecurityManager; 
                                  import org.apache.shiro.realm.Realm; 
                                  import org.apache.shiro.subject.Subject; 
                                  import org.apache.shiro.util.Factory;  
								    public class TestA {  
								   public static void main(String[] args) {    
								/*Realm*/    
								 //[1]解析shiro.ini文件 
                                  Factory<SecurityManager> factory =new 
                                  IniSecurityManagerFactory("classpath:shiro-jdbc.ini");    
								   //[2]通过SecurityManager工厂获得SecurityManager实例 
                                  SecurityManager securityManager = factory.getInstance();    
								  //[3]把SecurityManager对象设置到运行环境中 
                                  SecurityUtils.setSecurityManager(securityManager);    
								   //[4]通过SecurityUtils获得主体subject 
                                  Subject subject = SecurityUtils.getSubject();    
								   //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码 
                                  //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较 
                                  UsernamePasswordToken token =new UsernamePasswordToken("root","123");
                                   try { 
                                  //[6]进行身份的验证 
                                  subject.login(token);  
                                  //[7]通过方法判断是否登录成功
								     if(subject.isAuthenticated()){ 
                                  System.out.println("登录成功");
								       } 
                                  } catch (IncorrectCredentialsException e) {
								       System.out.println("登录失败");
								    
                                  }catch (UnknownAccountException e){    
								  System.out.println("用户名不正确"); 
                                  } 
                                  } 
                                  } | 
                           
                         
 
                             
                              [main] 
                                #获得数据源A 
                                dataSou=com.mchange.v2.c3p0.ComboPooledDataSource 
                                dataSou.driverClass=com.mysql.jdbc.Driver 
                                dataSou.jdbcUrl=jdbc:mysql://127.0.0.1:3306/shiro 
                                dataSou.user=root 
                                dataSou.password=root
                               
  #配置了jdbcRealmA 
                                  jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm 
                                  jdbcRealm.dataSource=$dataSou
  
                                  #获得数据源B 
                                  dataSou1=com.mchange.v2.c3p0.ComboPooledDataSource 
                                  dataSou1.driverClass=com.mysql.jdbc.Driver 
                                  dataSou1.jdbcUrl=jdbc:mysql://127.0.0.1:3306/shiro1 
                                  dataSou1.user=root 
                                  dataSou1.password=root
  
								  #配置了jdbcRealmB 
                                  jdbcRealm1=org.apache.shiro.realm.jdbc.JdbcRealm 
                                  jdbcRealm1.dataSource=$dataSou1
								  
  
                                  #配置验证器 
                                authenticationStrategy=org. apache .shiro.authc.pam.FirstSuccessfulStrategy 
                                 #设置securityManager中realm 
                                  securityManager.realms=$jdbcRealm,$jdbcRealm1 
                                securityManager.authenticator.authenticationStrategy 
                                =$authenticationStrategy | 
                           
                         
                            
                          七、如何自定义Realm 
                           
                          [1]为什么使用自定义 Realm 
                          我们使用 JDBCRealm 的时候发现,shiro 的底层自己封装了数据库 
                            表的名称和字段的名称,这样就造成了使用起来非常不方便 
                          [2]解决方案 
                            自定义 Realm 
                            我们如果自己定义 realm 的话,可以实现这个接口 
                            
                          自定义Realm,可以注入给securityManager更加灵活的安全数据源(例如,JDBCRealm中表和字段都限定了) 
                          通过实现Realm接口,或根据需求继承他的相应子类即可。 
                          
                            需求:使用自定义Realm提供数据源,从而实现认证 
                          
                            实现步骤: 
                          6.1添加jar包 
                            6.2编写自定义Realm 
                            6.3编写shiro.ini 
                            6.4编写测试类 
                         
                             
                              package com.bjsxt.shiro2; 
                                  import org.apache.shiro.authc.AuthenticationException; 
                                  import org.apache.shiro.authc.AuthenticationInfo; 
                                  import org.apache.shiro.authc.AuthenticationToken; 
                                  import org.apache.shiro.authc.SimpleAuthenticationInfo; 
                                  import org.apache.shiro.authz.AuthorizationInfo; 
                                  import org.apache.shiro.realm.AuthorizingRealm; 
                                  import org.apache.shiro.subject.PrincipalCollection; 
                                 import java.sql.Connection; 
                                  import java.sql.DriverManager; 
                                  import java.sql.PreparedStatement; 
                                  import java.sql.ResultSet;
								  
  public class UserRealm extends AuthorizingRealm 
                                  {
  
								  
                                  //认证 
                                  @Override 
                                protected AuthenticationInfo doGetAuthenticationInfo 
                                (AuthenticationToken authenticationToken) throws 
                                AuthenticationException {  
                                 
                                //System.out.println(authenticationToken .getPrincipal()); 
                                 
                                 try { 
                                  Class.forName("com.mysql.jdbc.Driver"); 
                                
                                Connection conn = DriverManager. getConnection 
                                ("jdbc:mysql://127.0.0.1:3306/shiro", 
                                "root", "root");  
                                 
                                PreparedStatement prepareStatement = conn.prepareStatement("select 
                                pwd from admin where uname =? ");  
                                 
                                prepareStatement.setObject (1,authenticationToken.getPrincipal()); 
								  
								  
   ResultSet rs = prepareStatement.executeQuery();
								  
  while (rs.next()){
								  
  
                                SimpleAuthenticationInfo info=new SimpleAuthenticationInfo 
                                (authenticationToken .getPrincipal(),rs.getString("pwd"),"userRealm"); 
                                 
                                  return info;
								  
  } 
                                  } catch (Exception e) { 
                                  e.printStackTrace(); 
                                  }
  
                                  return null; 
                                  }
  
                                 //授权 
                                  @Override 
                                protected AuthorizationInfo doGetAuthorizationInfo 
                                (PrincipalCollection principalCollection) { 
                                  return null; 
                                  }
  
                                  } | 
                           
                          
						
                             
                              package com.bjsxt.shiro2; 
                                 
                                import org.apache.shiro.SecurityUtils; 
                                  import org.apache.shiro.authc.IncorrectCredentialsException; 
                                  import org.apache.shiro.authc.UnknownAccountException; 
                                  import org.apache.shiro.authc.UsernamePasswordToken; 
                                  import org.apache.shiro.config.IniSecurityManagerFactory; 
                                  import org.apache.shiro.mgt.SecurityManager; 
                                  import org.apache.shiro.subject.Subject; 
                                  import org.apache.shiro.util.Factory;    
								  public class TestB {
								     public static void main(String[] args) {
								     /*Realm*/    
								//[1]解析shiro.ini文件 
                                  Factory<SecurityManager> factory =new 
                                  IniSecurityManagerFactory("classpath:shiro-jdbc2.ini");  
								    //[2]通过SecurityManager工厂获得SecurityManager实例 
                                  SecurityManager securityManager = factory.getInstance();  
								  
								    //[3]把SecurityManager对象设置到运行环境中 
                                  SecurityUtils.setSecurityManager(securityManager);
								       //[4]通过SecurityUtils获得主体subject 
                                  Subject subject = SecurityUtils.getSubject();
								       //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码 
                                  //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较 
                                  UsernamePasswordToken token =new UsernamePasswordToken("root","123");    
								   try { 
                                  //[6]进行身份的验证 
                                  subject.login(token);    
								   //[7]通过方法判断是否登录成功
								    if(subject.isAuthenticated()){ 
                                  System.out.println("登录成功");
								       } 
                                  } catch (IncorrectCredentialsException e) {    
								   System.out.println("登录失败");    
                                  }catch (UnknownAccountException e){  
                                  System.out.println("用户名不正确"); 
                                  } 
                                  } 
                                  } | 
                           
                          
                           
                               [main] 
                                #设置securityManager中realm 
                                userRealm=com.bjsxt.shiro2.UserRealm 
                                securityManager.realms=$userRealm | 
                           
                         
                          
                            【代码示例】 
                           realms 
                          
                             
                              package com.bjsxt.realms; 
                                 
                                 import java.net.ConnectException; 
                                  import java.security.interfaces.RSAKey; 
                                  import java.sql.Connection; 
                                  import java.sql.DriverManager; 
                                  import java.sql.ResultSet; 
                                  import java.sql.SQLException; 
                                  import java.sql.Statement;
								  
  import org.apache.shiro.authc.AuthenticationException; 
                                  import org.apache.shiro.authc.AuthenticationInfo; 
                                  import org.apache.shiro.authc.AuthenticationToken; 
                                  import org.apache.shiro.authc.SimpleAuthenticationInfo; 
                                  import org.apache.shiro.realm.AuthenticatingRealm;
								  
  import com.mysql.jdbc.Driver;
  
								public class CustomRealm extends AuthenticatingRealm 
                                  {
								  
   private String principal; 
                                  private String credentials; 
                                  private ResultSet rs; 
                                  private Statement state; 
                                  private Connection conn;
  
								   @Override 
                                  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken 
                                  token) throws AuthenticationException { 
                                  //使用JDBC,从数据库获取数据 
                                  try { 
                                  //1.注册驱动 
                                  Driver driver = new Driver(); 
                                  DriverManager.registerDriver(driver); 
                                  //2.获取连接对象 
                                  String url ="jdbc:mysql:///test"; 
                                  String user = "root"; 
                                  String password = "victor"; 
                                  conn = DriverManager.getConnection(url , user 
                                  , password ); 
                                  state = conn.createStatement(); 
                                  //4.执行sql语句 
                                  String sql = "select userName,passwd from 
                                  starLogin"; 
                                  rs = state.executeQuery(sql ); 
                                  //5.处理结果集 
                                  while (rs.next()) { 
                                  principal = rs.getString("userName"); 
                                  credentials = rs.getString("passwd"); 
                                  } 
                                  } catch (SQLException e) { 
                                  e.printStackTrace(); 
                                  }finally{ 
                                  if(rs != null){ 
                                  try { 
                                  rs.close(); 
                                  } catch (SQLException e) { 
                                  e.printStackTrace(); 
                                  } 
                                  } 
                                  if(state != null){ 
                                  try { 
                                  state.close(); 
                                  } catch (SQLException e) { 
                                  e.printStackTrace(); 
                                  } 
                                  } 
                                  if(conn != null){ 
                                  try { 
                                  conn.close(); 
                                  } catch (SQLException e) { 
                                  e.printStackTrace(); 
                                  } 
                                  } 
                                  } 
                                   
                                  SimpleAuthenticationInfo simpleAuthenticationInfo 
                                  = new SimpleAuthenticationInfo(principal, credentials, 
                                  "customRealm"); 
                                  return simpleAuthenticationInfo; 
                                  }
  
                                  } | 
                             
                           
                           AuthenticationTest 
                          
                             
                              package com.bjsxt.test; 
                                 
                                 import org.apache.shiro.SecurityUtils; 
                                  import org.apache.shiro.authc.UsernamePasswordToken; 
                                  import org.apache.shiro.config.IniSecurityManagerFactory; 
                                  import org.apache.shiro.mgt.SecurityManager; 
                                  import org.apache.shiro.subject.Subject; 
                                  import org.junit.Test;
  
								  //实现简单认证 
                                  public class AuthenticationTest { 
                                  @Test 
                                  public void testAuthentication(){ 
                                  //1.构建SecurityManager工厂 
                                  IniSecurityManagerFactory securityManagerFactory 
                                  = new IniSecurityManagerFactory("classpath:shiro.ini"); 
                                  //2.通过securityManagerFactory工厂获取SecurityManager实例 
                                  SecurityManager securityManager = securityManagerFactory.getInstance(); 
                                  //3.将securityManager设置到运行环境当中 
                                  SecurityUtils.setSecurityManager(securityManager); 
                                  //4.获取subject实例 
                                  Subject subject = SecurityUtils.getSubject(); 
                                  //5.创建用户名密码验证令牌Token 
                                  UsernamePasswordToken token = new UsernamePasswordToken("victor","123"); 
                                  //6.进行身份验证 
                                  subject.login(token); 
                                  //7.判断是否认证通过 
                                  System.out.println(subject.isAuthenticated()); 
                                  } 
                                  } | 
                             
                           
                           Shrio.ini 
                          
                             
                               [main] 
                                #配置Realm 
                                customRealm = com.bjsxt.realms.CustomRealm 
                                 #将Realm注入给SecurityManager 
                                  securityManager.realm = $customRealm | 
                             
                           
                          
                           
                            
                          八、密码加密实现方案 
                          8.1几种常见加密算法比较 
                          8.1.1对称加密算法(加密与解密密钥相同) 
                           
 
                            8.1.2非对称算法(加密密钥和解密密钥不同) 
                          
 
                            8.1.3 对称与非对称算法比较 
                           
 
                            8.1.4 散列算法比较‘ 
                           
 
                            8.2 MD5加密、加盐与迭代 
                          加盐: 
                            使用MD5存在一个问题,相同的password生产的Hash值是相同的,如 
                            果两个用户设置了相同的密码,那么数据库当就会存储相同的值,这样是极 
                            不安全的。 
                          加Salt可以一定程度上解决这一问题。所谓加Salt方法,就是加点 
                            “佐料”。其基本想法是这样的:当用户首次提供密码时(通常是注册时), 
                            由系统自动往这个密码里撒一些“佐料”,然后再散列。而当用户登录时,系统为用户提供的代码撒上同样的“佐料”,然后散列,再比较散列值,来确定密码是否正确。 
                          加盐原理: 
                            给原文加入随机数生成新的MD5值。 
                            迭代:加密的次数 
                            【代码示例】 
                           md5Test 
                          
                             
                               package com.bjsxt.test;
                                  
  import org.apache.shiro.crypto.hash.Md5Hash; 
                                  import org.junit.Test;  
                                 //MD5加密、加盐以及迭代 
                                  public class MD5Test { 
                                  @Test 
                                  public void testMD5(){ 
                                  //md5加密 
                                  Md5Hash md5 = new Md5Hash("123456"); 
                                  System.out.println(md5); 
                                  //加盐 
                                  md5 = new Md5Hash("123456", "bjsxt"); 
                                  System.out.println(md5); 
                                  //迭代 
                                  md5 = new Md5Hash("123456", "bjsxt", 
                                  2); 
                                  System.out.println(md5); 
                                  } 
                                  } | 
                             
                           
                          
                           
                          TestB.java 
                          
                             
                              package com.bjsxt.shiro3; 
                                   import org.apache.shiro.SecurityUtils; 
                                  import org.apache.shiro.authc.IncorrectCredentialsException; 
                                  import org.apache.shiro.authc.UnknownAccountException; 
                                  import org.apache.shiro.authc.UsernamePasswordToken; 
                                  import org.apache.shiro.config.IniSecurityManagerFactory; 
                                  import org.apache.shiro.mgt.SecurityManager; 
                                  import org.apache.shiro.subject.Subject; 
                                  import org.apache.shiro.util.Factory;  
								    public class TestB {
								     public static void main(String[] args) {
								    /*Realm*/  
								  //[1]解析shiro.ini文件 
                                  Factory<SecurityManager> factory =new 
                                  IniSecurityManagerFactory("classpath:shiro-jdbc3.ini");    
								   //[2]通过SecurityManager工厂获得SecurityManager实例 
                                  SecurityManager securityManager = factory.getInstance();    
								   //[3]把SecurityManager对象设置到运行环境中 
                                  SecurityUtils.setSecurityManager(securityManager);
								      //[4]通过SecurityUtils获得主体subject 
                                  Subject subject = SecurityUtils.getSubject();
								      //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码 
                                  //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较 
                                  UsernamePasswordToken token =new UsernamePasswordToken("root","111");  
								     try { 
                                  //[6]进行身份的验证 
                                  subject.login(token);
								       //[7]通过方法判断是否登录成功  
                                   if(subject.isAuthenticated()){ 
                                  System.out.println("登录成功");  
                                  } 
                                  } catch (IncorrectCredentialsException e) {  
                                   System.out.println("登录失败");  
                                 
  
                                  }catch (UnknownAccountException e){  
                                  System.out.println("用户名不正确"); 
                                  } 
                                  } 
                                  } | 
                             
                           
                           TestDemo.java 
                          
                             
                              package com.bjsxt.shiro3; 
                                 
                                 import org.apache.shiro.crypto.hash.Md5Hash; 
                                  public class TestDemo { 
                                  public static void main(String[] args) { 
                                  //使用MD5加密 
                                  Md5Hash md5=new Md5Hash("1111"); 
                                  System.out.println("1111=="+md5); 
                                  //加盐 
                                  md5=new Md5Hash("1111","sxt"); 
                                  System.out.println("1111=="+md5); 
                                  //迭代次数 
                                  md5=new Md5Hash("123","sxt",2); 
                                  System.out.println("1111=="+md5); 
                                 } 
                                 } | 
                             
                           
                           shiro-jdbc.ini 
                          
                             
                              [main] 
                                #设置securityManager中realm 
                                credentialsMatcher=org.apache.shiro.authc. credential.HashedCredentialsMatcher 
                                credentialsMatcher.hashAlgorithmName=md5 
                                credentialsMatcher.hashIterations=2 
                                 userRealm=com.bjsxt.shiro3.UserRealm 
                                  userRealm.credentialsMatcher=$credentialsMatcher 
                                  securityManager.realms=$userRealm | 
                             
                           
                          
                           
                            
                          8.3 凭证匹配器 
                          在Realm接口的实现类AuthenticatingRealm中有credentialsMatcher属性。 
                            意为凭证匹配器。常用来设置加密算法及迭代次数等。 
                          Shiro.ini 
                          
                             
                              |  [main]
                                 #配置凭证匹配器 
                                  credentialsMatcher=org.apache.shiro.authc. credential.HashedCredentialsMatcher 
                                   #设置凭证匹配器的相关属性 
                                  credentialsMatcher.hashAlgorithmName=MD5 
                                  credentialsMatcher.hashIterations=2
  #配置Realm 
                                  customRealm=com.bjsxt.realms.CustomRealm
  #配置Realm的凭证匹配器属性 
                                  customRealm.credentialsMatcher=$credentialsMatcher
  #将Realm注入给SecurityManager 
                                  securityManager.realm=$customRealm  | 
                             
                           
                           costomRealm 
                          
                             
                              package com.bjsxt.realms; 
                                 
                                 import java.net.ConnectException; 
                                  import java.security.interfaces.RSAKey; 
                                  import java.sql.Connection; 
                                  import java.sql.DriverManager; 
                                  import java.sql.ResultSet; 
                                  import java.sql.SQLException; 
                                  import java.sql.Statement; 
								   import org.apache.shiro.authc.AuthenticationException; 
                                  import org.apache.shiro.authc.AuthenticationInfo; 
                                  import org.apache.shiro.authc.AuthenticationToken; 
                                  import org.apache.shiro.authc.SimpleAuthenticationInfo; 
                                  import org.apache.shiro.realm.AuthenticatingRealm; 
                                  import org.apache.shiro.util.ByteSource;
								  
  import com.mysql.jdbc.Driver;
								
  public class CustomRealm extends AuthenticatingRealm 
                                  {
								  
   private String principal; 
                                  private String credentials; 
                                  private ResultSet rs; 
                                  private Statement state; 
                                  private Connection conn; 
                                  private String salt; 
								    @Override 
                                  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken 
                                  token) throws AuthenticationException { 
                                  //使用JDBC,从数据库获取数据 
                                  try { 
                                  //1.注册驱动 
                                  Driver driver = new Driver(); 
                                  DriverManager.registerDriver(driver); 
                                  //2.获取连接对象 
                                  String url ="jdbc:mysql:///test"; 
                                  String user = "root"; 
                                  String password = "victor"; 
                                  conn = DriverManager.getConnection(url , user 
                                  , password ); 
                                  state = conn.createStatement(); 
                                  //4.执行sql语句 
                                  String sql = "select userName,passwd,passwd_salt 
                                  from starLogin"; 
                                  rs = state.executeQuery(sql ); 
                                  //5.处理结果集 
                                  while (rs.next()) { 
                                  principal = rs.getString("userName"); 
                                  credentials = rs.getString("passwd"); 
                                  salt = rs.getString("passwd_salt"); 
                                  } 
                                  } catch (SQLException e) { 
                                  e.printStackTrace(); 
                                  }finally{ 
                                  if(rs != null){ 
                                  try { 
                                  rs.close(); 
                                  } catch (SQLException e) { 
                                  e.printStackTrace(); 
                                  } 
                                  } 
                                  if(state != null){ 
                                  try { 
                                  state.close(); 
                                  } catch (SQLException e) { 
                                  e.printStackTrace(); 
                                  } 
                                  } 
                                  if(conn != null){ 
                                  try { 
                                  conn.close(); 
                                  } catch (SQLException e) { 
                                  e.printStackTrace(); 
                                  } 
                                  } 
                                  } 
                                   
                                  ByteSource newSalt = ByteSource.Util.bytes(salt); 
                                  SimpleAuthenticationInfo simpleAuthenticationInfo 
                                  = new SimpleAuthenticationInfo(principal, credentials,newSalt 
                                  , "customRealm"); 
                                  return simpleAuthenticationInfo; 
                                  } 
                                  }
                                 | 
                             
                           
                           AutenticationTest 
                          
                             
                              package com.bjsxt.test; 
                                 
                                 import org.apache.shiro.SecurityUtils; 
                                  import org.apache.shiro.authc.UsernamePasswordToken; 
                                  import org.apache.shiro.config.IniSecurityManagerFactory; 
                                  import org.apache.shiro.mgt.SecurityManager; 
                                  import org.apache.shiro.subject.Subject; 
                                  import org.junit.Test;
								  
  //实现简单认证 
                                  public class AuthenticationTest { 
                                  @Test 
                                  public void testAuthentication(){ 
                                  //1.构建SecurityManager工厂 
                                IniSecurityManagerFactory securityManagerFactory 
                                = new IniSecurityManagerFactory("classpath:shiro.ini"); 
                                  //2.通过securityManagerFactory工厂获取SecurityManager实例 
                                  SecurityManager securityManager = securityManagerFactory.getInstance(); 
                                  //3.将securityManager设置到运行环境当中 
                                  SecurityUtils.setSecurityManager(securityManager); 
                                  //4.获取subject实例 
                                  Subject subject = SecurityUtils.getSubject(); 
                                  //5.创建用户名密码验证令牌Token 
                                UsernamePasswordToken token = new UsernamePasswordToken("victor","123456"); 
                                  //6.进行身份验证 
                                  subject.login(token); 
                                  //7.判断是否认证通过 
                                  System.out.println(subject.isAuthenticated()); 
                                  } 
                                  }  | 
                             
                           
                          
                           
                            
                          授权 
                            授权:给身份认证通过的任授予某些资源的访问权限 
                          
                            权限的粒度 粗粒度 细粒度 
                          
                            粗粒度 
                          
                            User 具有 CRUD 的操作 通常指的是表的操作 
                            细粒度 
                          
                            只允许查询 id=1 的用户 使用业务代码实现 
                            Shiro 的授权是粗粒度 
                          
                            角色:角色就是权限的集合 
                            Shiro 中代码的实现 
                          
                           详细见代码 
                          
                             
                               package com.bjsxt.shiro1;
                                 import org.apache.shiro.SecurityUtils; 
                                  import org.apache.shiro.authc.IncorrectCredentialsException; 
                                  import org.apache.shiro.authc.UsernamePasswordToken; 
                                  import org.apache.shiro.config.IniSecurityManagerFactory; 
                                  import org.apache.shiro.mgt.SecurityManager; 
                                  import org.apache.shiro.subject.Subject; 
                                  import org.apache.shiro.util.Factory;
  
								  import java.util.Arrays; 
								   public class TestA {
   public static void main(String[] args) { 
                                  //[1]解析shiro.ini文件 
                                  Factory<SecurityManager> factory =new 
                                  IniSecurityManagerFactory("classpath:shiro.ini"); 
								    //[2]通过SecurityManager工厂获得SecurityManager实例 
                                  SecurityManager securityManager = factory.getInstance(); 
								    //[3]把SecurityManager对象设置到运行环境中 
                                  SecurityUtils.setSecurityManager(securityManager);
   
								  //[4]通过SecurityUtils获得主体subject 
                                  Subject subject = SecurityUtils.getSubject();
  
								   //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码 
                                  //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较 
                                  UsernamePasswordToken token =new UsernamePasswordToken("zs","123");
   try { 
                                  //[6]进行身份的验证 
                                  subject.login(token);
  
								   } catch (IncorrectCredentialsException e) 
                                  { 
                                  System.out.println("登录失败"); 
                                  }
 
  
                                  //授权的查询
   //基于角色的授权 
                                  boolean flag = subject.hasRole("role1"); 
                                  //System.out.println(flag);
   //判断是否具有多个角色 
                                boolean[] booleans = subject.hasRoles(Arrays.asList 
                                ("role1", "role3"));  
                                  /*for(Boolean b:booleans){
								  
   System.out.println(b); 
                                  }*/
   //可以使用checkRole判断指定用户是否具有对应角色 
                                //如果指定用户下没有对应的角色就会抛出异常 UnauthorizedException 
                                  /* subject.checkRole("role3");
								  
   subject.checkRoles("role1","role2");*/
 
  
                                  //基于资源的授权 
                                  boolean flag2 = subject.isPermitted("iii");
  
								   //System.out.println(flag2);
   //判读是否具有多个资源 
                                boolean permittedAll = subject.isPermittedAll 
                                ("add", "oo", "ii"); 
                                  
								  //通过checkPermission 进行判断指定用户下是否有指定的资源 
                                  //如果没有就会抛出UnauthorizedException 
                                  subject.checkPermission("uu");
   
								  subject.checkPermissions("ii","ooo","add");
								  
 
  
                                  } 
                                  } | 
                             
                           
                           Role.java 
                          
                             
                               package com.bjsxt.shiro1;
                                   import org.apache.shiro.authz.annotation.RequiresRoles;
								
  public class Role { 
                                   
                                   } | 
                             
                           
                          
                           
                          Shiro 中的授权检查的 3 种方式 
                            A、 编程式 
                            B、 注解式 @RequiresRoles("管理员") public void 
                            aa(){ 
                            } 
                          
                           C、 标签配置 <shiro:hasPermission name="add"> 
                            <a>添加操作</a> </shiro:hasPermission> 
                            
                          自定义 Realm 实现授权 
                          我们仅仅通过配置文件指定授权是非常的不灵活的,在实际的应用中我们是将用户的信息和合权限信息保存到数据库中,我们是从数据库中获得用户的信息 
                            ,使用 JDBCRealm 进行授权 。使用 JDBCRealm 操作的时候也不是很灵活。所以我们一般使用自定义 
                            Realm 实现授权。 
                          
                             
                              package com.bjsxt.shiro; 
                                   import org.apache.shiro.authc.AuthenticationException; 
                                  import org.apache.shiro.authc.AuthenticationInfo; 
                                  import org.apache.shiro.authc.AuthenticationToken; 
                                  import org.apache.shiro.authc.SimpleAuthenticationInfo; 
                                  import org.apache.shiro.authz.AuthorizationInfo; 
                                  import org.apache.shiro.authz.SimpleAuthorizationInfo; 
                                  import org.apache.shiro.realm.AuthorizingRealm; 
                                  import org.apache.shiro.subject.PrincipalCollection;
  
								  import java.sql.Connection; 
                                  import java.sql.DriverManager; 
                                  import java.sql.PreparedStatement; 
                                  import java.sql.ResultSet; 
                                  import java.util.ArrayList; 
                                  import java.util.List;
  
								  public class UserRealm extends AuthorizingRealm 
                                  {
 
  
                                  //认证 
                                  @Override 
                                  protected AuthenticationInfo doGetAuthenticationInfo 
                                  (AuthenticationToken authenticationToken) throws 
                                  AuthenticationException { 
                                    //System.out.println(authenticationToken.getPrincipal());
  
								   try { 
                                  Class.forName("com.mysql.jdbc.Driver");
  
                                  Connection conn = DriverManager.getConnection 
                                  ("jdbc:mysql://127.0.0.1:3306/shiro", 
                                  "root", "root"); 
                                  
  
                                PreparedStatement prepareStatement = conn.prepareStatement 
                                ("select pwd from admin where uname =? "); 
                                   
                                prepareStatement.setObject (1,authenticationToken.getPrincipal()); 
                                 
                                  ResultSet rs = prepareStatement.executeQuery();
   
								  while (rs.next()){
  
                                SimpleAuthenticationInfo info=new SimpleAuthenticationInfo 
                                (authenticationToken.getPrincipal(), rs.getString("pwd"),"userRealm"); 
                                    return info;
   
								  } 
                                  } catch (Exception e) { 
                                  e.printStackTrace(); 
                                  }
 
  
                                  return null; 
                                  }
 
 
   
								  //授权 
                                  @Override 
                                  protected AuthorizationInfo doGetAuthorizationInfo 
                                  (PrincipalCollection principalCollection) { 
                                   
                                  String username = principalCollection.getPrimaryPrincipal().toString(); 
                                    //获得username 然后去数据库查询这个用户对应的角色,在根据角色查询出指定角色下对应的菜单, 
                                  //返回给指定角色下的所有菜单--List集合 
                                  System.out.println("username="+username);
   
								  //模拟数据库查的菜单 
                                  List<String> list =new ArrayList<>(); 
                                  list.add("updateUser"); 
                                  list.add("addUser"); 
                                  list.add("deleteUser");
  
                                SimpleAuthorizationInfo simpleAuthorizationInfo 
                                =new SimpleAuthorizationInfo(); 
                                    for(String l:list){ 
                                  simpleAuthorizationInfo.addStringPermission(l); 
                                  }
   return simpleAuthorizationInfo; 
                                  }
  
                                  } | 
                             
                            |