シロ基本使用まとめ

48915 ワード

1.概要
Apache Shiro          Java     ,      、  、        。

認証、認可:
認証は簡単に言えば、ログイン時にユーザー名とパスワードが完全に一致しているかどうかを判断することであり、あなたがあなたであることを証明することです.
権限は、認証に基づいて、ロールと権限の付与を行います.権限は、ユーザーがどのような操作を行うことができるかを決定します.
ロール、権限:
パーミッションは、ユーザーが操作を実行できるかどうかを定義します.
ロールは、権限のセットです.
通常、権限のセットを1つのロールにバインドし、1つ以上のロールを1つのユーザーに割り当てることで、権限の制御を実現します.すなわち、権限はロールによってユーザーに定義されます.ロールは権限の集合として、権限の管理を容易にします.
2.簡単なログイン機能を実現
  • shiro依存の追加
  •  <dependency>
        <groupId>org.apache.shirogroupId>
        <artifactId>shiro-coreartifactId>
        <version>1.3.2version>
    dependency>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>${junit.version}version>
        <scope>testscope>
    dependency>
  • プロファイルshiro.ini
  • [users]
    heqianqian = 12345666

    3.テストコードの作成
    public class SimpleLoginTest {
        @Test
        public void test() throws Exception {
            ShiroUtils.login("classpath:shiro/shiro.ini", "heqianqian", "12345666");
        }
    }
    public class ShiroUtils {
    
        public static Subject getSubject(String path) {
            IniSecurityManagerFactory factory = new IniSecurityManagerFactory(path);
            SecurityManager manager = factory.getInstance();
            SecurityUtils.setSecurityManager(manager);
            return SecurityUtils.getSubject();
        }
    
        public static Subject login(String path, String userName, String passWord) {
            Subject subject = getSubject(path);
            UsernamePasswordToken token = new UsernamePasswordToken(userName, passWord);
            try {
                subject.login(token);
                System.out.println("    ");
            } catch (UnknownAccountException e) {
                System.out.println("      ");
                e.printStackTrace();
            } catch (IncorrectCredentialsException e) {
                System.out.println("    ");
                e.printStackTrace();
            } catch (AuthenticationException e) {
                e.printStackTrace();
            }
    
            //subject.logout();
            //System.out.println("    ");
            return subject;
        }
    }
    
  • Subjectは私たちが登録した主体で、ここは橋に相当して、私たちのすべての操作は実際にSubjectを通じて私たちを助けなければなりません.
  • SecurityManagerはspring MVCのDispatcherServeretに類似しており、フロントエンドコントローラに類似した役割を果たす
  • Realmはセキュリティ・データ・ソースです.ユーザー名やパスワードのような情報をRealmに保存すると、Shiroは認証や認可などの一連の操作を完了するのに役立ちます.この例のRealmはIniRealm
  • と呼ばれています.
    3.JDBCRealmを使用
    前の例のデータが書かれているプロファイルでは、データベースからデータを読み取ることもできます.
  • 依存の追加
  •  <dependency>
        <groupId>org.apache.shirogroupId>
        <artifactId>shiro-coreartifactId>
        <version>1.3.2version>
    dependency>
    <dependency>
       <groupId>c3p0groupId>
       <artifactId>c3p0artifactId>
       <version>0.9.1.2version>
    dependency>
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>5.1.39version>
    dependency>
    <dependency>
         <groupId>log4jgroupId>
          <artifactId>log4jartifactId>
          <version>1.2.17version>
    dependency>
    <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>slf4j-apiartifactId>
        <version>${slf4j.version}version>
    dependency>
    <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>slf4j-log4j12artifactId>
        <version>${slf4j.version}version>
    dependency>
  • プロファイルjdbcRealmを作成する.ini
  • [main]
    #               ,            。
    ##JdbcRealm    users 
    jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
    dataSource = com.mchange.v2.c3p0.ComboPooledDataSource
    dataSource.driverClass = com.mysql.jdbc.Driver
    dataSource.user = root
    dataSource.password = ****
    #     dataSource           jdbcUrl ,           。
    dataSource.jdbcUrl = jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=UTF-8
    #     jdbcRealm           dataSource ,    dataSource              ,              `$`。
    jdbcRealm.dataSource = $dataSource
    securityManager.realms = $jdbcRealm
  • データベース構築
  • DROP DATABASE db_shiro;
    #       db_shiro
    CREATE DATABASE db_shiro DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
    #       db_shiro
    USE db_shiro;
    
    drop table if exists users;
    create table users(
      id int(11) not null auto_increment comment '  ',
      username varchar(20) default null comment '   ',
      password varchar(20) default null comment '  ',
      PRIMARY KEY (id)
    )engine=innodb auto_increment=1 default charset=utf8 comment '   ';
    
    insert into users(username,password) values('hqq','123456');

    注意:ここで作成したテーブルのテーブル名はusersです.JdbcRealmはデフォルトでusersテーブルのデータを検索します.
    JdbcRealmソース
    public class JdbcRealm extends AuthorizingRealm {
        protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
        protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";
        protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";
        protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";
    ...
    }

    4.試験方法の作成
    public class JdbcRealmTest {
    
        private String userName = "heqianqian";
    
        private String passWord = "123";
    
        private Logger logger = Logger.getLogger(JdbcRealmTest.class);
    
        @Test
        public void test() throws Exception {
            ShiroUtils.login("classpath:shiro/jdbcRealm.ini", userName, passWord);
        }
    }

    4.カスタムRealm
    方式一:implements Realm
    このようにして実現されるRealmは、認証操作のみを実現することができ、認証操作を実現することはできない.
    public class MapRealm implements Realm {
    
        private static Map users = new HashMap<>();
    
        static {
            users.put("heqianqian", "123");
            users.put("lucy", "456");
        }
    
        /**
         *      Realm  
         */
        @Override
        public String getName() {
            System.out.println("  Realm   ");
            return "My MapRealm";
        }
    
        /**
         *       Token
         */
        @Override
        public boolean supports(AuthenticationToken authenticationToken) {
            System.out.println("Map Realm        Token    ");
            //       UsernamePasswordToken     Token
            return authenticationToken instanceof UsernamePasswordToken;
        }
    
        /**
         *       
         */
        @Override
        public AuthenticationInfo getAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("Map Realm           ");
            String userName = (String) authenticationToken.getPrincipal();
            String passWord = new String((char[])authenticationToken.getCredentials());
            if (!users.containsKey(userName)) {
                System.out.println("     !");
            } else if (!users.get(userName).equals(passWord)) {
                System.out.println("    !");
            }
            return new SimpleAuthenticationInfo(userName, passWord, getName());
        }
    }
    

    プロファイルを作成するmapRealm.ini
    [main]
    #              Realm
    myMapRealm = heqianqian.shiro.realm.MapRealm
    #          Realm     securityManager   realms     
    securityManager.realms = $myMapRealm

    テスト
    public class MapRealmTest {
        @Test
        public void test() throws Exception {
            ShiroUtils.login("classpath:shiro/mapRealm.ini","heqianqian","123");
        }
    }

    方式2:extends AuthorizingRealm(認証操作もライセンス操作も実現できるため、比較的一般的な方法)
    public class MyStaticRealm extends AuthorizingRealm {
    
        /**
         *     
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            //     ,    
            return null;
        }
    
        /**
         *     
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("Static Realm       ");
            String userName = authenticationToken.getPrincipal().toString();
            String password = new String((char[]) authenticationToken.getCredentials());
            if (!"heqianqian".equals(userName)) {
                throw new UnknownAccountException("      ");
            } else if (!"123".equals(password)) {
                throw new IncorrectCredentialsException("    ");
            }
            return new SimpleAuthenticationInfo("heqianqian", "123", getName());
        }
    }
    

    プロファイルを作成するini
    [main]
    myStaticRealm = heqianqian.shiro.realm.MyStaticRealm
    securityManager.realms = $myStaticRealm

    テスト
     @Test
        public void testPermission() throws Exception {
            Subject subject = ShiroUtils.login("classpath:shiro/mystaticRealm.ini", "heqianqian", "123");
        }

    ナレッジポイントナレッジポイント:資格認定ポリシーの構成
    このとき、securityManagerのプロパティがrealmsである以上、いくつかのRealmを設定できることを説明しますが、認証の順序はどうなっていますか.
    では、いくつかのRealmについて、Shiroは、複数のReamlが同時に宣言された場合に、どのRealmが返す認証情報を採用するかを決定する構成を提供しています.これが私たちの認証ポリシーです.
    認証ポリシーには、主に次の3つがあります.
    1、FirstSuccessfulStrategy:Realm認証が成功すれば、最初のRealm認証が成功した認証情報だけを返し、その他は無視する.
    2、AtLeastOneSuccessfulStrategy:(これはデフォルトで使用される認証ポリシー、すなわち、構成されていない場合にShiroが採用する認証ポリシー)Realm認証が1つ成功すればよく、FirstSuccessfulStrategyとは異なり、すべてのRealm認証に成功した認証情報を返す.
    3、AllSuccessfulStrategy:すべてのRealm検証が成功してこそ成功し、すべてのRealm認証が成功した認証情報を返し、1つの失敗があれば失敗します.
    構成例
    #       
    allSuccessfulStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy
    securityManager.authenticator.authenticationStrategy = $allSuccessfulStrategy

    5.文字列ベースの役割と権限
    プロファイルの作成
    [users]
    hqq = 123,role1,role2
    lucy = 111,role1
    [roles]
    role1 = user:select
    role2 = user:add,user:update,user:delete

    ロールと権限のテスト
    public class RoleTest {
    
        @Test
        public void testHasRole() throws Exception {
            Subject subject = ShiroUtils.login("classpath:shiro/shiro-role.ini", "hqq", "123");
            assertEquals(true, subject.hasRole("role1"));
            assertEquals(true, subject.hasRole("role2"));
            assertEquals(true, subject.hasAllRoles(Arrays.asList("role1", "role2")));
            subject.logout();
        }
    
        @Test
        public void testCheckRole() throws Exception {
            Subject subject = ShiroUtils.login("classpath:shiro/shiro-role.ini", "hqq", "123");
            subject.checkRole("role1");
            subject.checkRole("role2");
            subject.checkRoles(Arrays.asList("role1", "role2"));
            assertEquals(true, subject.hasRole("role2"));
    
        }
    }
    
    public class PermissionTest {
    
        @Test
        public void testHasPermission() throws Exception {
            Subject subject = ShiroUtils.login("classpath:shiro/shiro-permission.ini", "hqq", "123");
            assertEquals(true, subject.isPermitted("user:select"));
            subject.isPermitted("user:select", "user:add", "user:delete", "user:update");
            assertEquals(true, subject.isPermittedAll("user:select", "user:select", "user:add", "user:delete", "user:update"));
            subject.logout();
        }
    
        @Test
        public void testCheckPermission() throws Exception {
            Subject subject = ShiroUtils.login("classpath:shiro/shiro-permission.ini", "hqq", "123");
            subject.checkPermission("user:select");
            subject.checkPermissions("user:select", "user:add", "user:delete", "user:update");
            subject.logout();
        }
    }

    6.カスタム権限解析器とロール解析器
    権限解決規則をカスタマイズするには
    手順1:Permissionインタフェースの実装
    public class MyPermission implements Permission {
    
        private String resourceId;
        private String operator;
        private String instanceId;
    
        public MyPermission() {
    
        }
    
        public MyPermission(String permissionStr) {
            String[] strs = permissionStr.split("\\+");
            if (strs.length > 1) {
                this.resourceId = strs[1];
            }
            if (this.resourceId == null || "".equals(this.resourceId)) {
                this.resourceId = "*";
            }
            if (strs.length > 2) {
                this.operator = strs[2];
            }
            if (strs.length > 3) {
                this.instanceId = strs[3];
            }
            if (this.instanceId == null || "".equals(this.instanceId)) {
                this.instanceId = "*";
            }
    
            System.out.println("    MyPermission   => " + this.toString());
        }
    
        /**
         * 【           】
         *                  ,
         *        ,   Realm      Permission   ini        PermissionResoler      Permission     
         *               
         */
        @Override
        public boolean implies(Permission permission) {
            if (!(permission instanceof MyPermission)) {
                return false;
            }
            MyPermission mp = (MyPermission) permission;
            if (!"*".equals(mp.resourceId) && !this.resourceId.equals(mp.resourceId)) {
                return false;
            }
            if (!"*".equals(mp.operator) && !this.operator.equals(mp.operator)) {
                return false;
            }
            if (!"*".equals(mp.instanceId) && !this.instanceId.equals(mp.instanceId)) {
                return false;
            }
            return true;
        }
    
        @Override
        public String toString() {
            return "MyPermission{" +
                    "resourceId='" + resourceId + '\'' +
                    ", operator='" + operator + '\'' +
                    ", instanceId='" + instanceId + '\'' +
                    '}';
        }
    }

    手順2:PermissionResolverインタフェースの実装
    PermissionResolverインタフェースを実装する意味は,Shiroが文字列の表現形式(表現特徴)に基づいて,どのようなPermissionを用いてマッチングするかを教えることである.
    public class MyPermissionResolver implements PermissionResolver {
        @Override
        public Permission resolvePermission(String s) {
        /*             “+”      ,          MyPermission ,         WildcardPermission        。*/
            if (s.startsWith("+")) {
                return new MyPermission(s);
            }
            return new WildcardPermission(s);
        }
    }

    説明:このコードは、権限文字列が「+」で始まる場合は、カスタムMyPermissionを使用します.そうしないと、デフォルトのWildcardPermissionを使用してこの文字列を解析します.
    ステップ3:認証ロジックの実装
    public class MyStaticRealm extends AuthorizingRealm {
    
        /**
         *     
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("Static Realm       ");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.addRole("r1");
            info.addRole("r2");
            info.addRole("role1");
            info.addStringPermission("+user+");
            info.addObjectPermission(new MyPermission("+user+add+1"));
            return info;
        }
    
        /**
         *     
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("Static Realm       ");
            String userName = authenticationToken.getPrincipal().toString();
            String password = new String((char[]) authenticationToken.getCredentials());
            if (!"heqianqian".equals(userName)) {
                throw new UnknownAccountException("      ");
            } else if (!"123".equals(password)) {
                throw new IncorrectCredentialsException("    ");
            }
            return new SimpleAuthenticationInfo("heqianqian", "123", getName());
        }
    }
    

    プロファイルの作成
    #          
    permissionResolver = heqianqian.shiro.permission.MyPermissionResolver
    authorizer.permissionResolver = permissionResolver
    securityManager.authorizer = $authorizer

    カスタムキャラクタマッチング
    手順1:RolePermissionResolverインタフェースの実装
    public class MyRolePermissionResolver implements RolePermissionResolver {
        @Override
        public Collection resolvePermissionsInRole(String s) {
            System.out.println("MyRolePermissionResolver");
            if (s.contains("role1")) {
                return Arrays.asList((Permission) new MyPermission("+user+add+2"));
            }
            return null;
        }
    }

    手順2:shiro.Iniで我々のRolePermissionResolverを構成する
    authorizer = org.apache.shiro.authz.ModularRealmAuthorizer
    
    ##  RolePermissionResolver
    rolePermissionResolver = heqianqian.shiro.role.MyRolePermissionResolver
    authorizer.rolePermissionResolver = rolePermissionResolver
    
    #          
    permissionResolver = heqianqian.shiro.permission.MyPermissionResolver
    authorizer.permissionResolver = permissionResolver
    securityManager.authorizer = $authorizer
    

    手順3:カスタムRealmのライセンスメソッドにロールを追加する
    public class MyStaticRealm extends AuthorizingRealm {
    
        /**
         *     
         * @param principalCollection
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("static Realm       ");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.addRole("role1");
            return info;
        }
    
        /**
         *     
         * @param token
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //   
        }
    }

    ステップ4:認証メソッドで指定したロールに対する権限がユーザーにあるかどうかを判断する
    currentSubject.checkPermission("+user+add+1");

    7.暗号化
    PasswordService service = new DefaultPasswordService();
    String str1 = service.encryptPassword("123456");
    String str2 = service.encryptPassword("123456");
    System.out.println(str1);
    System.out.println(str2);
    //                
    boolean boolean1 = service.passwordsMatch("123456",str1);
    System.out.println(boolean1);
    boolean boolean2 = service.passwordsMatch("123456",str2);
    System.out.println(boolean2)

    カスタムRealmの認証実装セクション:
    public class MyPasswordRealm extends AuthorizingRealm {
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            return null;
        }
    
        /**
         *   
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            // default
            String userName = (String) authenticationToken.getPrincipal();
            //String passWordFromDB = "$shiro1$SHA-256$500000$onR5YN4/BqH6toWLn9atsg==$g31FX9UERzy36yBlruzIZqGwCLf8V9P5p3hBrZQOAY0=";
            //md5+salt
            String passWordFromDB = "c39d11270c99cb00a13a6ac1e54effa2";
            String salt = "hqq";
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userName, passWordFromDB, getName());
            info.setCredentialsSalt(ByteSource.Util.bytes(salt.getBytes()));
            return info;
        }
    }

    プロファイル
    #      Shiro           
    passwordMatcher=org.apache.shiro.authc.credential.PasswordMatcher
    #        Realm  
    ;myPasswordRealm= heqianqian.shiro.realm.MyPasswordRealm
    #   passwordMatcher         Realm   
    myPasswordRealm.credentialsMatcher=$passwordMatcher
    #       Realm     securityManager  
    securityManager.realms=$myPasswordRealm

    えんを加える
    String originPassword = "123456";
    String salt = "hello";
    String md5 = new Md5Hash(originPassword,salt).toString();
    System.out.println(md5);
    public class MyPasswordRealm extends AuthorizingRealm {
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            return null;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            String username  = authenticationToken.getPrincipal().toString();
            // String password = new String((char[]) authenticationToken.getCredentials());
            //               username         
            String passwordFromDB = "eeb9bad681184779aa6570e402d6ef6c";
            String salt = "hello";
            SimpleAuthenticationInfo info= new SimpleAuthenticationInfo(username,passwordFromDB,getName());
            //          ,   ByteSource      
            info.setCredentialsSalt(ByteSource.Util.bytes(salt.getBytes()));
            return info;
        }
    }

    プロファイル
    #      Shiro           
    hashMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
    hashMatcher.hashAlgorithmName=md5
    hashMatcher.hashSalted=hello
    #        Realm  
    myPasswordRealm=com.liwei.realm.MyPasswordRealm
    #   passwordMatcher         Realm   
    myPasswordRealm.credentialsMatcher=$hashMatcher
    #       Realm     securityManager  
    securityManager.realms=$myPasswordRealm

    参考記事
    http://blog.csdn.net/lw_power?viewmode=contents