zoukankan      html  css  js  c++  java
  • Shiro中的Realm

    IniRealm可读取资源文件

    resources下创建user.ini:

    [users]
    lyf=123qwe,admin
    [roles]
    admin=user:delete,user:update
    public void testAuthentication(){
    
            //IniRealm可以读取resources下的指定文件
            IniRealm iniRealm = new IniRealm("classpath:user.ini");
    
            //认证第一步
            //1.构建SecurityManager环境
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            //将Realm放入环境中
            defaultSecurityManager.setRealm(iniRealm);
    
            //2.由主体来提交认证请求
            //设置主体SecurityManager环境
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            //通过工具类获得主体
            Subject subject = SecurityUtils.getSubject();
            //获得主体之后,提交认证,即登录
            //这里用UsernamePasswordToken存认证数据
            UsernamePasswordToken token = new UsernamePasswordToken("lyf","123qwe");
            //进行登录认证
            subject.login(token);
    
            System.out.println("是否认证:" + subject.isAuthenticated());
    
            subject.checkRole("admin");
    
            //检测是否具备用户删除的权限
            subject.checkPermission("user:delete");
        }

    运行结果:


    JdbcRealm可以连接数据库
    需要在pom.xml中导入依赖
         <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.45</version>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.6</version>
            </dependency>

    然后配置连接等,如下:

    public class JdbcRealmTest {
    
        //创建数据源
        DruidDataSource dataSource = new DruidDataSource();
        //设置jdbc的url等
        {
            dataSource.setUrl("jdbc:mysql://localhost:3306/test");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
        }
    
        @Test
        public void testAuthentication() {
    
            //JdbcRealm需要连接数据库,在pom总引入对应驱动包
            JdbcRealm jdbcRealm = new JdbcRealm();
            //设置jdbc数据源
            jdbcRealm.setDataSource(dataSource);
    
            //认证第一步
            //1.构建SecurityManager环境
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            //将Realm放入SecurityManager环境中
            defaultSecurityManager.setRealm(jdbcRealm);
    
            //2.由主体来提交认证请求
            //设置主体SecurityManager环境
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            //通过工具类获得主体
            Subject subject = SecurityUtils.getSubject();
            //获得主体之后,提交认证,即登录
            //这里用UsernamePasswordToken存认证数据
            UsernamePasswordToken token = new UsernamePasswordToken("lyf", "123qwe");
            //进行登录认证
            subject.login(token);
    
            System.out.println("是否认证:" + subject.isAuthenticated());
    
        }
    }

    这里要注意的是JdbcRealm中有默认的一些sql语句:

    根据sql去建一个users表:

    运行认证测试,结果如下:

    再看角色、授权,需要建立角色表user_roles:

    还有授权表roles_permissions:

     这里验证用户角色使用subject.checkRole("admin");或者subject.checkRoles("admin","user");区别就在于后者可以传入多个角色进行验证,

    但是这里要特别注意的是在设置jdbcRealm属性时,一定要把权限打开:

    jdbcRealm.setPermissionsLookupEnabled(true);

    否则就会以下报错:

    org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [user:select]
    
        at org.apache.shiro.authz.ModularRealmAuthorizer.checkPermission(ModularRealmAuthorizer.java:323)
        at org.apache.shiro.mgt.AuthorizingSecurityManager.checkPermission(AuthorizingSecurityManager.java:137)
        at org.apache.shiro.subject.support.DelegatingSubject.checkPermission(DelegatingSubject.java:209)
        at lyf.top.test.JdbcRealmTest.testJdbcRealm(JdbcRealmTest.java:55)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
        at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

    贴上正确的代码:

    public void testJdbcRealm() {
    
            //JdbcRealm需要连接数据库,在pom总引入对应驱动包
            JdbcRealm jdbcRealm = new JdbcRealm();
            //设置jdbc数据源
            jdbcRealm.setDataSource(dataSource);
            //设置权限开关,默认为false,若没有设置,
            // 在验证权限的时候,会报错Subject does not have permission
            jdbcRealm.setPermissionsLookupEnabled(true);
    
            //认证第一步
            //1.构建SecurityManager环境
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            //将Realm放入SecurityManager环境中
            defaultSecurityManager.setRealm(jdbcRealm);
    
            //2.由主体来提交认证请求
            //设置主体SecurityManager环境
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            //通过工具类获得主体
            Subject subject = SecurityUtils.getSubject();
            //获得主体之后,提交认证,即登录
            //创建Token令牌,这里用UsernamePasswordToken存认证数据
            UsernamePasswordToken token = new UsernamePasswordToken("lyf", "123qwe");
            //进行登录认证
            subject.login(token);
    
            System.out.println("是否认证:" + subject.isAuthenticated());
    
            //检验当前账号角色
            subject.checkRole("admin");
            //检验当前账号是否同时具备两个角色admin、user
            subject.checkRoles("admin","user");
    
            subject.checkPermission("user:select");
    
        }

    而在实际开发中,不可能用到它自带的sql,因为我们自己的表字段不可能跟它一样,所以需要使用自定义sql:

            //自定义登录验证的sql语句
            String sql = "select password from test_user where user_name = ?";
            jdbcRealm.setAuthenticationQuery(sql);
    
            //自定义验证角色的sql语句
            String rolSql = "select role_name from test_user_role where user_name = ?";
            jdbcRealm.setUserRolesQuery(rolSql);

    其他操作照常不变。


    自定义Realm

    首先创建自定义Realm,CustomRealm.java:

    public class CustomRealm extends AuthorizingRealm {
    
        Map<String,String > userMap = new HashMap<>(16);
    
        {
            userMap.put("lyf","123qwe");
            super.setName("customRealm");
        }
    
        //授权
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
            return null;
        }
    
        //认证
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
            //1.通过主体传过来的认证信息中去获取用户名
            String userName = (String)authenticationToken.getPrincipal();
    
            //2.通过用户名到数据库中获取凭证
            String password = getPasswordByUserName(userName);
            if (password == null){
                return null;
            }
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo
                    ("lyf",password,"customRealm");
    
            return authenticationInfo;
        }
    
        /**
         * 模拟数据库查询凭证
         * @param userName
         * @return
         */
        private String getPasswordByUserName(String userName){
    
            return userMap.get(userName);
        }
    }

    这里只写了认证,接着测试这个自定义的Realm:

    public class CustomRealmTest {
        @Test
        public void testAuthentication() {
    
            //创建自定义Realm对象
            CustomRealm customRealm = new CustomRealm();
    
    
            //认证第一步
            //1.构建SecurityManager环境
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(customRealm);
    
            //2.由主体来提交认证请求
            //设置主体SecurityManager环境
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            //通过工具类获得主体
            Subject subject = SecurityUtils.getSubject();
            //获得主体之后,提交认证,即登录
            //这里用UsernamePasswordToken存认证数据
            UsernamePasswordToken token = new UsernamePasswordToken("lyf", "123qwe");
            //进行登录认证
            subject.login(token);
    
            System.out.println("是否认证:" + subject.isAuthenticated());
    
            /*subject.checkRole("admin");
    
            //检测是否具备用户删除的权限
            subject.checkPermission("user:delete");*/
        }
    }

    运行结果如下:

    接着是写自定义Realm中的授权操作:

        //授权
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
            String userName = (String) principalCollection.getPrimaryPrincipal();
            //实际开发时这里是从数据库或者缓存中获取角色数据
            Set<String> roles = getRolesByUserName(userName);
    
            Set<String> permissions = getPermissionsByUserName();
            //将取来的角色数据与权限数据返回
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            //设置权限
            simpleAuthorizationInfo.setStringPermissions(permissions);
            //设置角色
            simpleAuthorizationInfo.setRoles(roles);
    
            return simpleAuthorizationInfo;
        }
    
        private Set<String> getPermissionsByUserName() {
            Set<String> sets= new HashSet<>();
            sets.add("user:delete");
            sets.add("user:add");
            return sets;
        }
    
        private Set<String> getRolesByUserName(String userName) {
            Set<String> sets = new HashSet<>();
            sets.add("admin");
            sets.add("user");
            return sets;
        }

    添加测试:

           subject.checkRole("admin");
           subject.checkPermissions("user:add","user:delete");

    运行结果如下:

  • 相关阅读:
    cloud-api-service和cloud-iopm-web提交merge方法
    Java知识点-判断null、空字符串和空格
    Windows本机搭建Redis
    api-gateway-engine知识点(2)
    能够提高开发效率的Eclipse实用操作
    IOP知识点(2)
    获取分辨率及dp/px换算
    Android软件自动更新(自定义处理,不使用第三方)
    友盟自动更新参数详解
    [Android]ping -c 1 -w 100 sina.cn的解析
  • 原文地址:https://www.cnblogs.com/xk920/p/10814771.html
Copyright © 2011-2022 走看看