Shiro之身份验证

    xiaoxiao2021-03-25  138

    principals即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。credentials是证明/凭证,即只有主体知道的安全值,如密码/数字证书等。最常见的principals和credentials组合就是用户/密码了。

    下面我们来看一个认证的例子,由于我们是用maven构建的实例,所以需要在pom.xml中添加依赖:

    <dependency>     <groupId>junit</groupId>     <artifactId>junit</artifactId>     <version>4.11-20120805-1225</version> </dependency>     <dependency>     <groupId>commons-logging</groupId>     <artifactId>commons-logging</artifactId>     <version>1.1.3</version> </dependency> <dependency>     <groupId>org.apache.shiro</groupId>     <artifactId>shiro-core</artifactId>     <version>1.2.3</version> </dependency>

    另外,准备一些用户微分凭据,shiro.ini:

    [users] zhang=123 wang=123

    测试用例:

    package org.shiro; import junit.framework.Assert; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.junit.Test; public class ShiroTest1{     @Test     public void shiro_test1(){         //获取SecurityManager工厂,此处使用ini配置文件初始化SecurityManager         Factory<org.apache.shiro.mgt.SecurityManager> factory =                  new IniSecurityManagerFactory("classpath:shiro.ini");         //得到SecurityManager实例并绑定给SecurityUtils         org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();         SecurityUtils.setSecurityManager(securityManager);         //得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)         Subject subject = SecurityUtils.getSubject();         UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");         try {             subject.login(token);         } catch (AuthenticationException e) {             System.err.println(e.getMessage());         }         //断言用户已经登录         Assert.assertEquals(true, subject.isAuthenticated());         //退出         subject.logout();     } }

    从上例中,我们可以看到shiro的身份认证流程,如果还没有明白,可以看看下图:

    首先调用Subject.login(token)进行登录,其会自动委托给SecurityManager,调用之前必须通过SecurityUtils.setSecurityManager()设置

    2.    SecurityManager负责真正的身份验证逻辑,它会委托给Authenticator进行身份验证

    3.    Authenticator才是真正的身份验证者,shiro API中核心的身份认证入口点,此处可以自定义插入自己的实现

    4.    Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证。

    5.    Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此外可以配置多个Realm,将按照相应的顺序及策略进行访问。

     

    Realm

    Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法。也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作。可以把Realm看成DataSource,即安全数据源。如我们前面的例子使用ini配置,它使用的是org.apache.shiro.realm.text.IniRealm。

    org.apache.shiro.realm.Realm接口如下:

    public interface Realm {     String getName();                                //返回一个唯一的Realm名字     boolean supports(AuthenticationToken token);     //判断此Realm是否支持此Token     AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)             throws AuthenticationException;          //根据Token获取认证信息 }

    单Realm配置实例如下:

    MyRealm.java:

    package org.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.realm.Realm; public class MyRealm implements Realm {     public String getName() {         return "myRealm";     }     public boolean supports(AuthenticationToken token) {         return token instanceof UsernamePasswordToken;     }     public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)             throws AuthenticationException {         System.out.println("myrealm~~~~~~~~~~~~~~~~~~~~~~~~~~");         //得到用户名           String username = (String)token.getPrincipal();          //得到密码           String password = new String((char[])token.getCredentials());          if(!"zhang".equals(username)) {               //如果用户名错误               throw new UnknownAccountException();          }           if(!"123".equals(password)) {               //如果密码错误               throw new IncorrectCredentialsException();          }           //如果身份认证验证成功,返回一个AuthenticationInfo实现;           return new SimpleAuthenticationInfo(username, password, getName());       } }

    shiro-realm.ini:

    myRealm=org.shiro.MyRealm securityManager.realms=$myRealm

    ShiroTest2.java:

    package org.shiro; import junit.framework.Assert; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.junit.Test; public class ShiroTest2{     @Test     public void shiro_test1(){         //获取SecurityManager工厂,此处使用ini配置文件初始化SecurityManager         Factory<org.apache.shiro.mgt.SecurityManager> factory =                  new IniSecurityManagerFactory("classpath:shiro-realm.ini");         //得到SecurityManager实例并绑定给SecurityUtils         org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();         SecurityUtils.setSecurityManager(securityManager);         //得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)         Subject subject = SecurityUtils.getSubject();         UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");         try {             subject.login(token);         } catch (AuthenticationException e) {             System.err.println(e.getMessage());         }         //断言用户已经登录         Assert.assertEquals(true, subject.isAuthenticated());         //退出         subject.logout();     } }

    多Realm配置实例如下:

    MyRealm1.java

    package org.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.realm.Realm; public class MyRealm1 implements Realm {     public String getName() {         return "myRealm1";     }     public boolean supports(AuthenticationToken token) {         return token instanceof UsernamePasswordToken;     }     public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)             throws AuthenticationException {         System.out.println("myRealm1--------------------");         //得到用户名           String username = (String)token.getPrincipal();          //得到密码           String password = new String((char[])token.getCredentials());          if(!"zhang".equals(username)) {               //如果用户名错误               throw new UnknownAccountException();          }           if(!"123".equals(password)) {               //如果密码错误               throw new IncorrectCredentialsException();          }           //如果身份认证验证成功,返回一个AuthenticationInfo实现;           return new SimpleAuthenticationInfo(username, password, getName());       } }

    MyRealm2.java:

    package org.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.realm.Realm; public class MyRealm2 implements Realm {     public String getName() {         return "myRealm2";     }     public boolean supports(AuthenticationToken token) {         return token instanceof UsernamePasswordToken;     }     public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)             throws AuthenticationException {         System.out.println("myRealm2--------------------");         //得到用户名           String username = (String)token.getPrincipal();          //得到密码           String password = new String((char[])token.getCredentials());          if(!"zhang".equals(username)) {               //如果用户名错误               throw new UnknownAccountException();          }           if(!"123".equals(password)) {               //如果密码错误               throw new IncorrectCredentialsException();          }           //如果身份认证验证成功,返回一个AuthenticationInfo实现;           return new SimpleAuthenticationInfo(username, password, getName());       } }

    shiro-multi-realm.ini:

    myRealm1=org.shiro.MyRealm1 myRealm2=org.shiro.MyRealm2 securityManager.realms=$myRealm1,$myRealm2

    ShiroTest3.java

    package org.shiro; import junit.framework.Assert; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.junit.Test; public class ShiroTest3{     @Test     public void shiro_test1(){         //获取SecurityManager工厂,此处使用ini配置文件初始化SecurityManager         Factory<org.apache.shiro.mgt.SecurityManager> factory =                  new IniSecurityManagerFactory("classpath:shiro-multi-realm.ini");         //得到SecurityManager实例并绑定给SecurityUtils         org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();         SecurityUtils.setSecurityManager(securityManager);         //得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)         Subject subject = SecurityUtils.getSubject();         UsernamePasswordToken token = new UsernamePasswordToken("zhang","123");         try {             subject.login(token);         } catch (AuthenticationException e) {             System.err.println(e.getMessage());         }         //断言用户已经登录         Assert.assertEquals(true, subject.isAuthenticated());         //退出         subject.logout();     } }

    注意ini配置中,都是通过$name来引用自定义的Realm的。另外,securityManager会按照realms指定的顺序进行身份认证。如果删除了“securityManager.realms=$myRealm1,$myRealm2”,那么securityManager会按照realm声明的顺序进行使用(即无需设置realms属性,其会自动发现)。当我们显示指定realm后,其他没有指定realm将被忽略。

     

    shiro默认提供的Realm

    以后一般继承AuthorizingRealm即可,其继承了AuthenticatingRealm(即身份验证),而且也间接继承了CachingRealm(带有缓存实现)。

     

    JDBC Realm使用

    示例,我们先在pom.xml中添加两年操作数据库的依赖

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>     <groupId>apl</groupId>     <artifactId>shiro-test</artifactId>     <version>0.0.1-SNAPSHOT</version>     <dependencies>         <dependency>             <groupId>junit</groupId>             <artifactId>junit</artifactId>             <version>4.11-20120805-1225</version>         </dependency>         <dependency>             <groupId>commons-logging</groupId>             <artifactId>commons-logging</artifactId>             <version>1.1.3</version>         </dependency>         <dependency>             <groupId>org.apache.shiro</groupId>             <artifactId>shiro-core</artifactId>             <version>1.2.3</version>         </dependency>         <dependency>             <groupId>mysql</groupId>             <artifactId>mysql-connector-java</artifactId>             <version>5.1.25</version>         </dependency>         <dependency>             <groupId>com.alibaba</groupId>             <artifactId>druid</artifactId>             <version>0.2.23</version>         </dependency>     </dependencies> </project>

    shiro-jdbc-realm.ini

    dataSource=com.alibaba.druid.pool.DruidDataSource dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql://localhost:3306/shiro dataSource.username=root dataSource.password=root jdbcRealm.dataSource=$dataSource jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm securityManager.realms=$jdbcRealm

    ShiroTest4.java测试用例:

    public class ShiroTest4 {     @Test     public void testJDBCRealm() {         //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager         Factory<org.apache.shiro.mgt.SecurityManager> factory =                 new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini");         //2、得到SecurityManager实例 并绑定给SecurityUtils         org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();         SecurityUtils.setSecurityManager(securityManager);         //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)         Subject subject = SecurityUtils.getSubject();         UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");         try {             //4、登录,即身份验证             subject.login(token);         } catch (AuthenticationException e) {             //5、身份验证失败             e.printStackTrace();         }         Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录         //6、退出         subject.logout();     } }
    转载请注明原文地址: https://ju.6miu.com/read-13168.html

    最新回复(0)