• Shiro认证、角色、权限


    Apache Shiro 是 Java 的一个安全框架。
    Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等。

    Shiro的内置Realm:IniRealm和JdbcRealm

    编写测试案例之前需要添加shiro的相关依赖:

    <dependencies>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-core</artifactId>
                <version>1.4.0</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>RELEASE</version>
            </dependency>
            <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>
        </dependencies>

    项目的目录结构:

    一、使用SimpleAccountRealm测试认证授权

    SimpleAccountRealm功能简单,不能实现权限功能,很多时候需要自己重新定义。

    package com.czhappy.test;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.realm.SimpleAccountRealm;
    import org.apache.shiro.subject.Subject;
    import org.junit.Before;
    import org.junit.Test;
    
    /**
     * 测试shiro认证授权
     */
    
    public class AuthenticationTest {
    
        SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
    
        @Before
        public void addUser(){
            simpleAccountRealm.addAccount("chen", "123456", "admin");
        }
    
        @Test
        public void testAuthentication(){
            //创建SecurityManager环境
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(simpleAccountRealm);
            //主体提交认证请求
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("chen", "123456");
            subject.login(token);
    
            System.out.println("isAuthenticated="+subject.isAuthenticated());
    
            //验证角色授权
            subject.checkRole("admin");
            //退出
            subject.logout();
    
        }
    }

    二、使用IniRealm测试认证授权

    编写user.ini文件:

    [users]
    chen=123456,admin
    [roles]
    admin=user:delete,user:update

    编写测试案例:

    package com.czhappy.test;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.realm.text.IniRealm;
    import org.apache.shiro.subject.Subject;
    import org.junit.Test;
    
    /**
     * IniRealm测试
     */
    public class IniRealmTest {
    
        @Test
        public void testAuthentication() {
            IniRealm iniRealm = new IniRealm("classpath:user.ini");
            //创建SecurityManager环境
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(iniRealm);
            //主体提交认证请求
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("chen", "123456");
            subject.login(token);
    
            System.out.println("isAuthenticated=" + subject.isAuthenticated());
            subject.checkRole("admin");
            subject.checkPermission("user:delete");
    
        }
    }

    三、使用JdbcRealm测试认证授权

    使用JdbcRealm需要连接数据操作,在此我们新建三张表

      

    由于使用的是系统自己JdbcRealm,操作数据库需要和源码中的表名一致.

    package com.czhappy.test;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.realm.jdbc.JdbcRealm;
    import org.apache.shiro.realm.text.IniRealm;
    import org.apache.shiro.subject.Subject;
    import org.junit.Test;
    /**
     * JdbcRealm测试
     */
    
    public class JdbcRealmTest {
    
        DruidDataSource dataSource = new DruidDataSource();
        {
            dataSource.setUrl("jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=true");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
        }
    
        @Test
        public void testAuthentication() {
            JdbcRealm jdbcRealm = new JdbcRealm();
            jdbcRealm.setDataSource(dataSource);
            //权限开关打开,默认是关闭的
            jdbcRealm.setPermissionsLookupEnabled(true);
            //创建SecurityManager环境
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(jdbcRealm);
            //主体提交认证请求
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("chen", "123456");
            subject.login(token);
    
            System.out.println("isAuthenticated=" + subject.isAuthenticated());
    
            subject.checkRole("admin");
            subject.checkPermission("user:select");
    
        }
    
    }

    四、自己编写sql的调用JdbcRealm认证授权

    新建2张表

     

    package com.czhappy.test;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.realm.jdbc.JdbcRealm;
    import org.apache.shiro.subject.Subject;
    import org.junit.Test;
    
    /**
     * JdbcRealm测试
     */
    
    public class SelfJdbcRealmTest {
    
        DruidDataSource dataSource = new DruidDataSource();
        {
            dataSource.setUrl("jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=true");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
        }
    
        @Test
        public void testAuthentication() {
            JdbcRealm jdbcRealm = new JdbcRealm();
            jdbcRealm.setDataSource(dataSource);
            //权限开关打开,默认是关闭的
            jdbcRealm.setPermissionsLookupEnabled(true);
    
            String sql = "select password from test_user where user_name = ?";
            jdbcRealm.setAuthenticationQuery(sql);
    
            String roleSql = "select role_name from test_user_roles where user_name = ?";
            jdbcRealm.setUserRolesQuery(roleSql);
    
            //创建SecurityManager环境
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(jdbcRealm);
            //主体提交认证请求
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "654321");
            subject.login(token);
    
            System.out.println("isAuthenticated=" + subject.isAuthenticated());
    
            subject.checkRole("user");
    //        subject.checkPermission("user:select");
    
        }
    
    }

    权限的测试可以参照角色,创建表、编写相关的sql语句

    五、自定义Realm实现认证授权

    package com.czhappy.realm;
    
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthenticatingRealm;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * 自定义Realm
     */
    public class CustomRealm extends AuthorizingRealm {
    
        Map<String, String> userMap = new HashMap<String, String>(16);
        {
            userMap.put("chen", "123456");
            super.setName("customRealm");
        }
    
        //角色权限验证
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            String userName = (String) principalCollection.getPrimaryPrincipal();
            //从数据库或者缓存中获取角色数据
            Set<String> roleSet = getRolesByUserName(userName);
    
            //从数据库或者缓存中获取权限数据
            Set<String> permissionSet = getPermissionsByUserName(userName);
    
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.setRoles(roleSet);
            simpleAuthorizationInfo.setStringPermissions(permissionSet);
            return simpleAuthorizationInfo;
        }
    
        /**
         * 模拟从数据库或者缓存中获取权限数据
         * @param userName
         * @return
         */
        private Set<String> getPermissionsByUserName(String userName) {
            Set<String> sets = new HashSet<String>();
            sets.add("user:add");
            sets.add("user:delete");
            return sets;
        }
    
        /**
         * 模拟从数据库或者缓存中获取角色数据
         * @param userName
         * @return
         */
        private Set<String> getRolesByUserName(String userName) {
            Set<String> sets = new HashSet<String>();
            sets.add("admin");
            sets.add("user");
            return sets;
        }
    
        //登录验证
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //从主体传过来的认证信息中获取用户名
            String userName = (String) authenticationToken.getPrincipal();
            //通过用户名到数据库中获取凭证
            String password = getPasswordByUsername(userName);
    
            if(password == null){
                return null;
            }
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo
                    (userName, password, "customRealm");
            return simpleAuthenticationInfo;
        }
    
        /**
         * 模拟数据库访问
         * @param userName
         * @return
         */
        private String getPasswordByUsername(String userName) {
            return userMap.get(userName);
        }
    }

    测试认证授权:

    package com.czhappy.test;
    
    import com.czhappy.realm.CustomRealm;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.realm.text.IniRealm;
    import org.apache.shiro.subject.Subject;
    import org.junit.Test;
    
    public class CustomRealmTest {
    
        @Test
        public void testAuthentication() {
            CustomRealm customRealm = new CustomRealm();
            //创建SecurityManager环境
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(customRealm);
            //主体提交认证请求
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("chen", "123456");
            subject.login(token);
    
            System.out.println("isAuthenticated=" + subject.isAuthenticated());
            subject.checkRole("admin");
            subject.checkPermissions("user:delete", "user:add");
    
        }
    }
  • 相关阅读:
    ArrayList源码剖析
    Qt线程外使用Sleep
    malloc、calloc和realloc比较
    C++各大名库
    Qt 编译boost
    VC++ 设置控件显示文本的前景色、背景色以及字体
    std::map的操作:插入、修改、删除和遍历
    time.h文件中包含的几个函数使用时须注意事项
    赋值操作符和拷贝构造函数
    virtual析构函数的作用
  • 原文地址:https://www.cnblogs.com/chenzheng8975/p/9474897.html
Copyright © 2020-2023  润新知