shiro身份验证

来源:互联网 发布:电路原理图软件 编辑:程序博客网 时间:2024/06/14 04:37

1.场景还原

    Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它非常实用又简单易懂,今天笔者就shiro的身份验证讲解一下,希望小伙伴能够受益。

2.概念梳理

 Subject :主体(用户)

 Realm:验证主体的数据源

3.验证步骤

①加入shiro依赖

<dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-core</artifactId>    <version>1.2.2</version></dependency>
②自定义主体数据源realm,集成Realm

public class MyRealm1 implements Realm {    @Override    public String getName() {        return "myrealm1";    }    @Override    public boolean supports(AuthenticationToken token) {        return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token    }    @Override    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {        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());    }}

③测试自定义数据源

@Testpublic void testCustomRealm() {    //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager    Factory<org.apache.shiro.mgt.SecurityManager> factory =            new IniSecurityManagerFactory("classpath:shiro-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();}
resources下新建shiro-realm.ini

[main]#声明一个realmmyRealm1=realm.MyRealm1#指定securityManagerrealms实现securityManager.realms=$myRealm1

多个realm配置

[main]#声明一个realmmyRealm1=realm.MyRealm1myRealm2=realm.MyRealm2#指定securityManagerrealms实现securityManager.realms=$myRealm1,$myRealm2

测试结果:


表明验证顺利通过!

主体数据源还可以直接写用户信息shiro.ini

[users]zhang=123wang=123
表明zhang/123,wang/123两个用户,相同地,验证也可通过;

④连接数据得到主体数据源

1>shiro-jdbc-realm.ini

[main]jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealmdataSource=com.alibaba.druid.pool.DruidDataSourcedataSource.driverClassName=com.mysql.jdbc.DriverdataSource.url=jdbc:mysql://localhost:3306/shirodataSource.username=rootdataSource.password=rootjdbcRealm.dataSource=$dataSourcesecurityManager.realms=$jdbcRealm
2>测试类

@Testpublic 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("liyang", "123");    try {        //4、登录,即身份验证        subject.login(token);    } catch (AuthenticationException e) {        //5、身份验证失败        e.printStackTrace();    }    if(subject.isAuthenticated()){        System.out.print("登陆成功");    }else{        System.out.print("登陆失败");    }    Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录    //6、退出    subject.logout();}

3>本地数据库数据


测试结果:


4.认证策略详解

SecurityManager 接口继承了 Authenticator,另外还有一个 ModularRealmAuthenticator 实现,其委托给多个 Realm 进行验证,验证规则通过 AuthenticationStrategy 接口指定,默认提供的实现:
FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证成功的认证信息,其他的忽略;
AtLeastOneSuccessfulStrategy:只要有一个 Realm 验证成功即可,和 FirstSuccessfulStrategy不同,返回所有 Realm 身份验证成功的认证信息;
AllSuccessfulStrategy:所有 Realm 验证成功才算成功,且返回所有 Realm 身份验证成功的认证信息,如果有一个失败就失败了。
ModularRealmAuthenticator 默认使用 AtLeastOneSuccessfulStrategy 策略。

①shiro-atLeatOne-success.ini

[main]#指定securityManagerauthenticator实现authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticatorsecurityManager.authenticator=$authenticator#指定securityManager.authenticatorauthenticationStrategyallSuccessfulStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategysecurityManager.authenticator.authenticationStrategy=$allSuccessfulStrategymyRealm1=realm.MyRealm1myRealm2=realm.MyRealm2myRealm3=realm.MyRealm3securityManager.realms=$myRealm1,$myRealm2,$myRealm3
②shrio-fisrt-success.ini

[main]#指定securityManagerauthenticator实现authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticatorsecurityManager.authenticator=$authenticator#指定securityManager.authenticatorauthenticationStrategyallSuccessfulStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategysecurityManager.authenticator.authenticationStrategy=$allSuccessfulStrategymyRealm1=realm.MyRealm1myRealm2=realm.MyRealm2myRealm3=realm.MyRealm3securityManager.realms=$myRealm1,$myRealm2,$myRealm3
③shiro-all-success.ini

[main]#指定securityManagerauthenticator实现authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticatorsecurityManager.authenticator=$authenticator#指定securityManager.authenticatorauthenticationStrategyallSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategysecurityManager.authenticator.authenticationStrategy=$allSuccessfulStrategymyRealm1=realm.MyRealm1myRealm2=realm.MyRealm2myRealm3=realm.MyRealm3securityManager.realms=$myRealm1,$myRealm3
然后测试

public class AuthenticatorTest {    @Test    public void testAllSuccessfulStrategyWithSuccess() {        login("classpath:shiro-authenticator-all-success.ini");        Subject subject = SecurityUtils.getSubject();        //得到一个身份集合,其包含了Realm验证成功的身份信息        PrincipalCollection principalCollection = subject.getPrincipals();              System.out.print(principalCollection.asList().get(1));        Assert.assertEquals(2, principalCollection.asList().size());    }       @Test    public void testAtLeastOneSuccessfulStrategyWithSuccess() {        login("classpath:shiro-authenticator-atLeastOne-success.ini");        Subject subject = SecurityUtils.getSubject();        //得到一个身份集合,其包含了Realm验证成功的身份信息        PrincipalCollection principalCollection = subject.getPrincipals();        System.out.print(principalCollection.asList().get(0));        Assert.assertEquals(2, principalCollection.asList().size());    }    @Test    public void testFirstOneSuccessfulStrategyWithSuccess() {        login("classpath:shiro-authenticator-first-success.ini");        Subject subject = SecurityUtils.getSubject();        //得到一个身份集合,其包含了第一个Realm验证成功的身份信息        PrincipalCollection principalCollection = subject.getPrincipals();        Assert.assertEquals(1, principalCollection.asList().size());    }      private void login(String configFile) {        //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager        Factory<org.apache.shiro.mgt.SecurityManager> factory =                new IniSecurityManagerFactory(configFile);        //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");        subject.login(token);        System.out.println(subject.isAuthenticated());    }    @After    public void tearDown() throws Exception {        ThreadContext.unbindSubject();//退出时请解除绑定Subject到线程 否则对下次测试造成影响    }}

 好了,大伙按需get!我是张星,欢迎加去博主技术交流群,群号:313145288