shiro身份验证

缺乏、安全感 2022-06-14 11:47 1614阅读 0赞

1.场景还原

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

2.概念梳理

Subject :主体(用户)

Realm:验证主体的数据源

3.验证步骤

①加入shiro依赖

  1. <dependency>
  2. <groupId>org.apache.shiro</groupId>
  3. <artifactId>shiro-core</artifactId>
  4. <version>1.2.2</version>
  5. </dependency>

②自定义主体数据源realm,集成Realm

  1. public class MyRealm1 implements Realm {
  2. @Override
  3. public String getName() {
  4. return "myrealm1";
  5. }
  6. @Override
  7. public boolean supports(AuthenticationToken token) {
  8. return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token
  9. }
  10. @Override
  11. public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  12. String username = (String)token.getPrincipal(); //得到用户名
  13. String password = new String((char[])token.getCredentials()); //得到密码
  14. if(!"zhang".equals(username)) {
  15. throw new UnknownAccountException(); //如果用户名错误
  16. }
  17. if(!"123".equals(password)) {
  18. throw new IncorrectCredentialsException(); //如果密码错误
  19. }
  20. //如果身份认证验证成功,返回一个AuthenticationInfo实现;
  21. return new SimpleAuthenticationInfo(username, password, getName());
  22. }
  23. }

③测试自定义数据源

  1. @Test
  2. public void testCustomRealm() {
  3. //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
  4. Factory<org.apache.shiro.mgt.SecurityManager> factory =
  5. new IniSecurityManagerFactory("classpath:shiro-realm.ini");
  6. //2、得到SecurityManager实例 并绑定给SecurityUtils
  7. org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
  8. SecurityUtils.setSecurityManager(securityManager);
  9. //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
  10. Subject subject = SecurityUtils.getSubject();
  11. UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
  12. try {
  13. //4、登录,即身份验证
  14. subject.login(token);
  15. } catch (AuthenticationException e) {
  16. //5、身份验证失败
  17. e.printStackTrace();
  18. }
  19. Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录
  20. //6、退出
  21. subject.logout();
  22. }

resources下新建shiro-realm.ini

  1. [main] #声明一个realm
  2. myRealm1=realm.MyRealm1
  3. #指定securityManager的realms实现
  4. securityManager.realms=$myRealm1

多个realm配置

  1. [main] #声明一个realm
  2. myRealm1=realm.MyRealm1
  3. myRealm2=realm.MyRealm2
  4. #指定securityManager的realms实现
  5. securityManager.realms=$myRealm1,$myRealm2

测试结果:

Center

表明验证顺利通过!

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

  1. [users] zhang=123
  2. wang=123

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

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

1>shiro-jdbc-realm.ini

  1. [main] jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
  2. dataSource=com.alibaba.druid.pool.DruidDataSource
  3. dataSource.driverClassName=com.mysql.jdbc.Driver
  4. dataSource.url=jdbc:mysql://localhost:3306/shiro
  5. dataSource.username=root
  6. dataSource.password=root
  7. jdbcRealm.dataSource=$dataSource
  8. securityManager.realms=$jdbcRealm

2>测试类

  1. @Test
  2. public void testJDBCRealm() {
  3. //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
  4. Factory<org.apache.shiro.mgt.SecurityManager> factory =
  5. new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini");
  6. //2、得到SecurityManager实例 并绑定给SecurityUtils
  7. org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
  8. SecurityUtils.setSecurityManager(securityManager);
  9. //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
  10. Subject subject = SecurityUtils.getSubject();
  11. UsernamePasswordToken token = new UsernamePasswordToken("liyang", "123");
  12. try {
  13. //4、登录,即身份验证
  14. subject.login(token);
  15. } catch (AuthenticationException e) {
  16. //5、身份验证失败
  17. e.printStackTrace();
  18. }
  19. if(subject.isAuthenticated()){
  20. System.out.print("登陆成功");
  21. }else{
  22. System.out.print("登陆失败");
  23. }
  24. Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录
  25. //6、退出
  26. subject.logout();
  27. }

3>本地数据库数据

Center 1

测试结果:

Center 2

4.认证策略详解

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

①shiro-atLeatOne-success.ini

  1. [main] #指定securityManager的authenticator实现
  2. authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
  3. securityManager.authenticator=$authenticator
  4. #指定securityManager.authenticator的authenticationStrategy
  5. allSuccessfulStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
  6. securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
  7. myRealm1=realm.MyRealm1
  8. myRealm2=realm.MyRealm2
  9. myRealm3=realm.MyRealm3
  10. securityManager.realms=$myRealm1,$myRealm2,$myRealm3

②shrio-fisrt-success.ini

  1. [main] #指定securityManager的authenticator实现
  2. authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
  3. securityManager.authenticator=$authenticator
  4. #指定securityManager.authenticator的authenticationStrategy
  5. allSuccessfulStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategy
  6. securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
  7. myRealm1=realm.MyRealm1
  8. myRealm2=realm.MyRealm2
  9. myRealm3=realm.MyRealm3
  10. securityManager.realms=$myRealm1,$myRealm2,$myRealm3

③shiro-all-success.ini

  1. [main] #指定securityManager的authenticator实现
  2. authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
  3. securityManager.authenticator=$authenticator
  4. #指定securityManager.authenticator的authenticationStrategy
  5. allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
  6. securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
  7. myRealm1=realm.MyRealm1
  8. myRealm2=realm.MyRealm2
  9. myRealm3=realm.MyRealm3
  10. securityManager.realms=$myRealm1,$myRealm3

然后测试

  1. public class AuthenticatorTest {
  2. @Test
  3. public void testAllSuccessfulStrategyWithSuccess() {
  4. login("classpath:shiro-authenticator-all-success.ini");
  5. Subject subject = SecurityUtils.getSubject();
  6. //得到一个身份集合,其包含了Realm验证成功的身份信息
  7. PrincipalCollection principalCollection = subject.getPrincipals();
  8. System.out.print(principalCollection.asList().get(1));
  9. Assert.assertEquals(2, principalCollection.asList().size());
  10. }
  11. @Test
  12. public void testAtLeastOneSuccessfulStrategyWithSuccess() {
  13. login("classpath:shiro-authenticator-atLeastOne-success.ini");
  14. Subject subject = SecurityUtils.getSubject();
  15. //得到一个身份集合,其包含了Realm验证成功的身份信息
  16. PrincipalCollection principalCollection = subject.getPrincipals();
  17. System.out.print(principalCollection.asList().get(0));
  18. Assert.assertEquals(2, principalCollection.asList().size());
  19. }
  20. @Test
  21. public void testFirstOneSuccessfulStrategyWithSuccess() {
  22. login("classpath:shiro-authenticator-first-success.ini");
  23. Subject subject = SecurityUtils.getSubject();
  24. //得到一个身份集合,其包含了第一个Realm验证成功的身份信息
  25. PrincipalCollection principalCollection = subject.getPrincipals();
  26. Assert.assertEquals(1, principalCollection.asList().size());
  27. }
  28. private void login(String configFile) {
  29. //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
  30. Factory<org.apache.shiro.mgt.SecurityManager> factory =
  31. new IniSecurityManagerFactory(configFile);
  32. //2、得到SecurityManager实例 并绑定给SecurityUtils
  33. org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
  34. SecurityUtils.setSecurityManager(securityManager);
  35. //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
  36. Subject subject = SecurityUtils.getSubject();
  37. UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
  38. subject.login(token);
  39. System.out.println(subject.isAuthenticated());
  40. }
  41. @After
  42. public void tearDown() throws Exception {
  43. ThreadContext.unbindSubject();//退出时请解除绑定Subject到线程 否则对下次测试造成影响
  44. }
  45. }

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

发表评论

表情:
评论列表 (有 0 条评论,1614人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Apache Shiro 身份验证

    身份验证,即在应用中谁能证明他就是他本人。一般提供如他们的身份ID一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。 在shiro中,用户需要提供princi

    相关 Shiro学习(2)身份验证

    身份验证:即在应用中谁能证明他就是他本人。一般提供如他们的身份ID一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。 在shiro中,用户需要提供princ

    相关 shiro身份验证

    1.场景还原     Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它非常实用又简单易懂,今天笔者就shiro的身份验

    相关 Shiro(二)之身份验证

    一、身份验证 即在应用中谁能证明他就是他本人。一般提供如他们的身份 ID 一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。 在 shiro 中,用户需

    相关 Shiro--身份验证

    身份验证 身份验证: 即在应用中谁能证明他就是他本人。一般提供如他们的身份ID一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。

    相关 Apache Shiro身份验证

    主要概念 身份验证:一般需要提供身份ID等一些标识信息来表明登录者的身份,如提供email,用户名/密码来证明。 在shiro中,用户需要提供principals(身