• 2017.2.7 开涛shiro教程-第六章-Realm及相关对象(一)


    原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398

    根据下载的pdf学习。

    第六章 Realm及相关对象

    1.用户、角色、权限的关系

    用户和角色是多对多,角色和权限也是多对多。

    用户和权限通过角色建立关系。

    角色是权限的集合。

    (1)表准备

    用户表:

    角色表:

    剩下的表类似,就不一一解释了。分别是权限表,用户-角色表,角色权限表。

    (2)表对应的实体

    2.环境准备

    (1)pom.xml

    3.Service和Dao层

    (1)Service层

    1 public interface PermissionService {
    2     public Permission createPermission(Permission permission);
    3     public void deletePermission(Long permissionId);
    4 }
    View Code
    public interface RoleService {
        public Role createRole(Role role);
        public void deleteRole(Long roleId);
    
        /**
         * 添加角色-权限之间关系
         * @param roleId
         * @param permissionIds
         */
        public void correlationPermissions(Long roleId, Long... permissionIds);
    
        /**
         * 移除角色-权限之间关系
         * @param roleId
         * @param permissionIds
         */
        public void uncorrelationPermissions(Long roleId, Long... permissionIds);
    
    }
    View Code
    public interface UserService {
        /**
         * 创建用户
         * @param user
         */
        public User createUser(User user);
    
        /**
         * 修改密码
         * @param userId
         * @param newPassword
         */
        public void changePassword(Long userId, String newPassword);
    
        /**
         * 添加用户-角色关系
         * @param userId
         * @param roleIds
         */
        public void correlationRoles(Long userId, Long... roleIds);
    
        /**
         * 移除用户-角色关系
         * @param userId
         * @param roleIds
         */
        public void uncorrelationRoles(Long userId, Long... roleIds);
    
        /**
         * 根据用户名查找用户
         * @param username
         * @return
         */
        public User findByUsername(String username);
    
        /**
         * 根据用户名查找其角色
         * @param username
         * @return
         */
        public Set<String> findRoles(String username);
    
        /**
         * 根据用户名查找其权限
         * @param username
         * @return
         */
        public Set<String> findPermissions(String username);
    
    }
    View Code

    (2)Service实现层

    public class PermissionServiceImpl implements PermissionService {
    
        private PermissionDao permissionDao = new PermissionDaoImpl();
    
        public Permission createPermission(Permission permission) {
            return permissionDao.createPermission(permission);
        }
    
        public void deletePermission(Long permissionId) {
            permissionDao.deletePermission(permissionId);
        }
    }
    View Code
    public class RoleServiceImpl implements RoleService {
    
        private RoleDao roleDao = new RoleDaoImpl();
    
    
        public Role createRole(Role role) {
            return roleDao.createRole(role);
        }
    
        public void deleteRole(Long roleId) {
            roleDao.deleteRole(roleId);
        }
    
        /**
         * 添加角色-权限之间关系
         * @param roleId
         * @param permissionIds
         */
        public void correlationPermissions(Long roleId, Long... permissionIds) {
            roleDao.correlationPermissions(roleId, permissionIds);
        }
    
        /**
         * 移除角色-权限之间关系
         * @param roleId
         * @param permissionIds
         */
        public void uncorrelationPermissions(Long roleId, Long... permissionIds) {
            roleDao.uncorrelationPermissions(roleId, permissionIds);
        }
    
    }
    View Code
    public class UserServiceImpl implements UserService {
    
        private UserDao userDao = new UserDaoImpl();
        private PasswordHelper passwordHelper = new PasswordHelper();
    
        /**
         * 创建用户
         * @param user
         */
        public User createUser(User user) {
            //加密密码
            passwordHelper.encryptPassword(user);
            return userDao.createUser(user);
        }
    
        /**
         * 修改密码
         * @param userId
         * @param newPassword
         */
        public void changePassword(Long userId, String newPassword) {
            User user =userDao.findOne(userId);
            user.setPassword(newPassword);
            passwordHelper.encryptPassword(user);
            userDao.updateUser(user);
        }
    
        /**
         * 添加用户-角色关系
         * @param userId
         * @param roleIds
         */
        public void correlationRoles(Long userId, Long... roleIds) {
            userDao.correlationRoles(userId, roleIds);
        }
    
    
        /**
         * 移除用户-角色关系
         * @param userId
         * @param roleIds
         */
        public void uncorrelationRoles(Long userId, Long... roleIds) {
            userDao.uncorrelationRoles(userId, roleIds);
        }
    
        /**
         * 根据用户名查找用户
         * @param username
         * @return
         */
        public User findByUsername(String username) {
            return userDao.findByUsername(username);
        }
    
        /**
         * 根据用户名查找其角色
         * @param username
         * @return
         */
        public Set<String> findRoles(String username) {
            return userDao.findRoles(username);
        }
    
        /**
         * 根据用户名查找其权限
         * @param username
         * @return
         */
        public Set<String> findPermissions(String username) {
            return userDao.findPermissions(username);
        }
    
    }
    View Code
    import com.github.zhangkaitao.shiro.chapter6.entity.User;
    import org.apache.shiro.crypto.RandomNumberGenerator;
    import org.apache.shiro.crypto.SecureRandomNumberGenerator;
    import org.apache.shiro.crypto.hash.SimpleHash;
    import org.apache.shiro.util.ByteSource;
    
    public class PasswordHelper {
    
        private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
    
        private String algorithmName = "md5";
        private final int hashIterations = 2;
    
        public void encryptPassword(User user) {
    
            user.setSalt(randomNumberGenerator.nextBytes().toHex());
    
            String newPassword = new SimpleHash(
                    algorithmName,
                    user.getPassword(),
                    ByteSource.Util.bytes(user.getCredentialsSalt()),
                    hashIterations).toHex();
    
            user.setPassword(newPassword);
        }
    }
    View Code

    (3)Dao层

    public interface PermissionDao {
        public Permission createPermission(Permission permission);
        public void deletePermission(Long permissionId);
    }
    View Code
    public interface RoleDao {
    
        public Role createRole(Role role);
        public void deleteRole(Long roleId);
    
        public void correlationPermissions(Long roleId, Long... permissionIds);
        public void uncorrelationPermissions(Long roleId, Long... permissionIds);
    
    }
    View Code
    public interface UserDao {
    
        public User createUser(User user);
        public void updateUser(User user);
        public void deleteUser(Long userId);
    
        public void correlationRoles(Long userId, Long... roleIds);
        public void uncorrelationRoles(Long userId, Long... roleIds);
    
        User findOne(Long userId);
        User findByUsername(String username);
    
        Set<String> findRoles(String username);
        Set<String> findPermissions(String username);
    }
    View Code

    (4)dao实现层

    import com.github.zhangkaitao.shiro.chapter6.JdbcTemplateUtils;
    import com.github.zhangkaitao.shiro.chapter6.entity.Permission;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.PreparedStatementCreator;
    import org.springframework.jdbc.support.GeneratedKeyHolder;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    public class PermissionDaoImpl implements PermissionDao {
    
        private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();
    
        public Permission createPermission(final Permission permission) {
            final String sql = "insert into sys_permissions(permission, description, available) values(?,?,?)";
    
            GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
            jdbcTemplate.update(new PreparedStatementCreator() {
                @Override
                public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                    PreparedStatement psst = connection.prepareStatement(sql,  new String[] { "id" });
                    psst.setString(1, permission.getPermission());
                    psst.setString(2, permission.getDescription());
                    psst.setBoolean(3, permission.getAvailable());
                    return psst;
                }
            }, keyHolder);
            permission.setId(keyHolder.getKey().longValue());
    
            return permission;
        }
    
        public void deletePermission(Long permissionId) {
            //首先把与permission关联的相关表的数据删掉
            String sql = "delete from sys_roles_permissions where permission_id=?";
            jdbcTemplate.update(sql, permissionId);
    
            sql = "delete from sys_permissions where id=?";
            jdbcTemplate.update(sql, permissionId);
        }
    
    }
    View Code
    import com.github.zhangkaitao.shiro.chapter6.JdbcTemplateUtils;
    import com.github.zhangkaitao.shiro.chapter6.entity.Role;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.PreparedStatementCreator;
    import org.springframework.jdbc.support.GeneratedKeyHolder;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    public class RoleDaoImpl implements RoleDao {
    
        private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();
    
        public Role createRole(final Role Role) {
            final String sql = "insert into sys_roles(role, description, available) values(?,?,?)";
    
            GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
            jdbcTemplate.update(new PreparedStatementCreator() {
                @Override
                public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                    PreparedStatement psst = connection.prepareStatement(sql, new String[] { "id" });
                    psst.setString(1, Role.getRole());
                    psst.setString(2, Role.getDescription());
                    psst.setBoolean(3, Role.getAvailable());
                    return psst;
                }
            }, keyHolder);
            Role.setId(keyHolder.getKey().longValue());
    
            return Role;
        }
    
        public void deleteRole(Long roleId) {
            //首先把和role关联的相关表数据删掉
            String sql = "delete from sys_users_roles where role_id=?";
            jdbcTemplate.update(sql, roleId);
    
            sql = "delete from sys_roles where id=?";
            jdbcTemplate.update(sql, roleId);
        }
    
        @Override
        public void correlationPermissions(Long roleId, Long... permissionIds) {
            if(permissionIds == null || permissionIds.length == 0) {
                return;
            }
            String sql = "insert into sys_roles_permissions(role_id, permission_id) values(?,?)";
            for(Long permissionId : permissionIds) {
                if(!exists(roleId, permissionId)) {
                    jdbcTemplate.update(sql, roleId, permissionId);
                }
            }
        }
    
    
        @Override
        public void uncorrelationPermissions(Long roleId, Long... permissionIds) {
            if(permissionIds == null || permissionIds.length == 0) {
                return;
            }
            String sql = "delete from sys_roles_permissions where role_id=? and permission_id=?";
            for(Long permissionId : permissionIds) {
                if(exists(roleId, permissionId)) {
                    jdbcTemplate.update(sql, roleId, permissionId);
                }
            }
        }
    
        private boolean exists(Long roleId, Long permissionId) {
            String sql = "select count(1) from sys_roles_permissions where role_id=? and permission_id=?";
            return jdbcTemplate.queryForObject(sql, Integer.class, roleId, permissionId) != 0;
        }
    
    }
    View Code
    import com.github.zhangkaitao.shiro.chapter6.JdbcTemplateUtils;
    import com.github.zhangkaitao.shiro.chapter6.entity.User;
    import org.springframework.jdbc.core.BeanPropertyRowMapper;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.PreparedStatementCreator;
    import org.springframework.jdbc.support.GeneratedKeyHolder;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    public class UserDaoImpl implements UserDao {
    
        private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();
    
        public User createUser(final User user) {
            final String sql = "insert into sys_users(username, password, salt, locked) values(?,?,?, ?)";
    
            GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
            jdbcTemplate.update(new PreparedStatementCreator() {
                @Override
                public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                    PreparedStatement psst = connection.prepareStatement(sql, new String[] { "id" });
                    psst.setString(1, user.getUsername());
                    psst.setString(2, user.getPassword());
                    psst.setString(3, user.getSalt());
                    psst.setBoolean(4, user.getLocked());
                    return psst;
                }
            }, keyHolder);
    
            user.setId(keyHolder.getKey().longValue());
            return user;
        }
    
        public void updateUser(User user) {
            String sql = "update sys_users set username=?, password=?, salt=?, locked=? where id=?";
            jdbcTemplate.update(sql, user.getUsername(), user.getPassword(), user.getSalt(), user.getLocked(), user.getId());
        }
    
        public void deleteUser(Long userId) {
            String sql = "delete from sys_users where id=?";
            jdbcTemplate.update(sql, userId);
        }
    
        @Override
        public void correlationRoles(Long userId, Long... roleIds) {
            if(roleIds == null || roleIds.length == 0) {
                return;
            }
            String sql = "insert into sys_users_roles(user_id, role_id) values(?,?)";
            for(Long roleId : roleIds) {
                if(!exists(userId, roleId)) {
                    jdbcTemplate.update(sql, userId, roleId);
                }
            }
        }
    
        @Override
        public void uncorrelationRoles(Long userId, Long... roleIds) {
            if(roleIds == null || roleIds.length == 0) {
                return;
            }
            String sql = "delete from sys_users_roles where user_id=? and role_id=?";
            for(Long roleId : roleIds) {
                if(exists(userId, roleId)) {
                    jdbcTemplate.update(sql, userId, roleId);
                }
            }
        }
    
        private boolean exists(Long userId, Long roleId) {
            String sql = "select count(1) from sys_users_roles where user_id=? and role_id=?";
            return jdbcTemplate.queryForObject(sql, Integer.class, userId, roleId) != 0;
        }
    
    
        @Override
        public User findOne(Long userId) {
            String sql = "select id, username, password, salt, locked from sys_users where id=?";
            List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper(User.class), userId);
            if(userList.size() == 0) {
                return null;
            }
            return userList.get(0);
        }
    
        @Override
        public User findByUsername(String username) {
            String sql = "select id, username, password, salt, locked from sys_users where username=?";
            List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper(User.class), username);
            if(userList.size() == 0) {
                return null;
            }
            return userList.get(0);
        }
    
        @Override
        public Set<String> findRoles(String username) {
            String sql = "select role from sys_users u, sys_roles r,sys_users_roles ur where u.username=? and u.id=ur.user_id and r.id=ur.role_id";
            return new HashSet(jdbcTemplate.queryForList(sql, String.class, username));
        }
    
        @Override
        public Set<String> findPermissions(String username) {
            //TODO 此处可以优化,比如查询到role后,一起获取roleId,然后直接根据roleId获取即可
            String sql = "select permission from sys_users u, sys_roles r, sys_permissions p, sys_users_roles ur, sys_roles_permissions rp where u.username=? and u.id=ur.user_id and r.id=ur.role_id and r.id=rp.role_id and p.id=rp.permission_id";
            return new HashSet(jdbcTemplate.queryForList(sql, String.class, username));
        }
    }
    View Code

    4.Realm

    (1)配置

    (2)代码

    import com.github.zhangkaitao.shiro.chapter6.service.UserService;
    import com.github.zhangkaitao.shiro.chapter6.service.UserServiceImpl;
    import com.github.zhangkaitao.shiro.chapter6.entity.User;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    
    public class UserRealm extends AuthorizingRealm {
    
        private UserService userService = new UserServiceImpl();
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {//授权
            String username = (String)principals.getPrimaryPrincipal();
    
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            authorizationInfo.setRoles(userService.findRoles(username));
            authorizationInfo.setStringPermissions(userService.findPermissions(username));
    
            return authorizationInfo;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//认证
            String username = (String)token.getPrincipal();
            User user = userService.findByUsername(username);
    
            if(user == null) {
                throw new UnknownAccountException();//没找到帐号
            }
    
            if(Boolean.TRUE.equals(user.getLocked())) {
                throw new LockedAccountException(); //帐号锁定
            }
    
            //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    user.getUsername(), //用户名
                    user.getPassword(), //密码
                    ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
                    getName()  //realm name
            );
            return authenticationInfo;
        }
    }
    View Code

     5.测试

    包含这几种情况:登录成功、用户名错误、密码错误、密码超出重试次数、有/没有角色、有/没有权限的测试。
    (1)测试基类

    import com.github.zhangkaitao.shiro.chapter6.service.*;
    import com.github.zhangkaitao.shiro.chapter6.entity.Permission;
    import com.github.zhangkaitao.shiro.chapter6.entity.Role;
    import com.github.zhangkaitao.shiro.chapter6.entity.User;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.config.IniSecurityManagerFactory;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.util.Factory;
    import org.apache.shiro.util.ThreadContext;
    import org.junit.After;
    import org.junit.Before;
    
    public abstract class BaseTest {
    
        protected PermissionService permissionService = new PermissionServiceImpl();
        protected RoleService roleService = new RoleServiceImpl();
        protected UserService userService = new UserServiceImpl();
    
        protected String password = "123";
    
        protected Permission p1;
        protected Permission p2;
        protected Permission p3;
        protected Role r1;
        protected Role r2;
        protected User u1;
        protected User u2;
        protected User u3;
        protected User u4;
    
        @Before
        public void setUp() {
            JdbcTemplateUtils.jdbcTemplate().update("delete from sys_users");
            JdbcTemplateUtils.jdbcTemplate().update("delete from sys_roles");
            JdbcTemplateUtils.jdbcTemplate().update("delete from sys_permissions");
            JdbcTemplateUtils.jdbcTemplate().update("delete from sys_users_roles");
            JdbcTemplateUtils.jdbcTemplate().update("delete from sys_roles_permissions");
    
            //1、新增权限
            p1 = new Permission("user:create", "用户模块新增", Boolean.TRUE);
            p2 = new Permission("user:update", "用户模块修改", Boolean.TRUE);
            p3 = new Permission("menu:create", "菜单模块新增", Boolean.TRUE);
            permissionService.createPermission(p1);
            permissionService.createPermission(p2);
            permissionService.createPermission(p3);
            //2、新增角色
            r1 = new Role("admin", "管理员", Boolean.TRUE);
            r2 = new Role("user", "用户管理员", Boolean.TRUE);
            roleService.createRole(r1);
            roleService.createRole(r2);
            //3、关联角色-权限
            roleService.correlationPermissions(r1.getId(), p1.getId());
            roleService.correlationPermissions(r1.getId(), p2.getId());
            roleService.correlationPermissions(r1.getId(), p3.getId());
    
            roleService.correlationPermissions(r2.getId(), p1.getId());
            roleService.correlationPermissions(r2.getId(), p2.getId());
    
            //4、新增用户
            u1 = new User("zhang", password);
            u2 = new User("li", password);
            u3 = new User("wu", password);
            u4 = new User("wang", password);
            u4.setLocked(Boolean.TRUE);
            userService.createUser(u1);
            userService.createUser(u2);
            userService.createUser(u3);
            userService.createUser(u4);
            //5、关联用户-角色
            userService.correlationRoles(u1.getId(), r1.getId());
    
        }
    
        @After
        public void tearDown() throws Exception {
            ThreadContext.unbindSubject();//退出时请解除绑定Subject到线程 否则对下次测试造成影响
        }
    
        protected void login(String configFile, String username, String password) {
            //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(username, password);
    
            subject.login(token);
        }
    
        public Subject subject() {
            return SecurityUtils.getSubject();
        }
    
    }
    View Code

    (2)测试类

    import com.github.zhangkaitao.shiro.chapter6.BaseTest;
    import junit.framework.Assert;
    import org.apache.shiro.authc.ExcessiveAttemptsException;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.LockedAccountException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.junit.Test;
    
    public class UserRealmTest extends BaseTest {
        
    
        @Test
        public void testLoginSuccess() {
            login("classpath:shiro.ini", u1.getUsername(), password);
            Assert.assertTrue(subject().isAuthenticated());
        }
    
        @Test(expected = UnknownAccountException.class)
        public void testLoginFailWithUnknownUsername() {
            login("classpath:shiro.ini", u1.getUsername() + "1", password);
        }
    
        @Test(expected = IncorrectCredentialsException.class)
        public void testLoginFailWithErrorPassowrd() {
            login("classpath:shiro.ini", u1.getUsername(), password + "1");
        }
    
        @Test(expected = LockedAccountException.class)
        public void testLoginFailWithLocked() {
            login("classpath:shiro.ini", u4.getUsername(), password + "1");
        }
    
        @Test(expected = ExcessiveAttemptsException.class)
        public void testLoginFailWithLimitRetryCount() {
            for(int i = 1; i <= 5; i++) {
                try {
                    login("classpath:shiro.ini", u3.getUsername(), password + "1");
                } catch (Exception e) {/*ignore*/}
            }
            login("classpath:shiro.ini", u3.getUsername(), password + "1");
    
            //需要清空缓存,否则后续的执行就会遇到问题(或者使用一个全新账户测试)
        }
    
        @Test
        public void testHasRole() {
            login("classpath:shiro.ini", u1.getUsername(), password );
            Assert.assertTrue(subject().hasRole("admin"));
        }
    
        @Test
        public void testNoRole() {
            login("classpath:shiro.ini", u2.getUsername(), password);
            Assert.assertFalse(subject().hasRole("admin"));
        }
    
        @Test
        public void testHasPermission() {
            login("classpath:shiro.ini", u1.getUsername(), password);
            Assert.assertTrue(subject().isPermittedAll("user:create", "menu:create"));
        }
    
        @Test
        public void testNoPermission() {
            login("classpath:shiro.ini", u2.getUsername(), password);
            Assert.assertFalse(subject().isPermitted("user:create"));
        }
    
    }
    View Code
  • 相关阅读:
    POJ2182Lost Cows
    BZOJ4003: [JLOI2015]城池攻占
    POJ1635Subway tree systems
    BZOJ1005: [HNOI2008]明明的烦恼
    POJ1182 NOI2001 食物链
    栈的链式实现
    栈的数组实现
    链表ADT的实现
    #ifndef的用法
    using namespace std
  • 原文地址:https://www.cnblogs.com/lyh421/p/6378191.html
Copyright © 2020-2023  润新知