shiro+ssm详细整合教程

第一步

这是一个很好的shiro学习网址:http://jinnianshilongnian.iteye.com/blog/2049092

在进行下面的步骤之前,您必须先拥有一个maven管理的ssm项目

第二步:准备数据库

这里需要我们准备shiro需要的权限表

shiro+ssm详细整合教程_第1张图片

这里我给大家提供mysql的建表脚本,直接运行即可



SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `sys_permissions`
-- ----------------------------
DROP TABLE IF EXISTS `sys_permissions`;
CREATE TABLE `sys_permissions` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `permission` varchar(100) DEFAULT NULL COMMENT '权限名',
  `description` varchar(100) DEFAULT NULL COMMENT '描述',
  `available` int(11) DEFAULT NULL COMMENT '是否可用,0表示可用,1表示不可用',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_permissions
-- ----------------------------
INSERT INTO `sys_permissions` VALUES ('1', 'user:create', '添加用户', '0');
INSERT INTO `sys_permissions` VALUES ('2', 'user:read', '查询用户', '0');
INSERT INTO `sys_permissions` VALUES ('3', 'user:update', '修改用户', '0');
INSERT INTO `sys_permissions` VALUES ('4', 'user:delete', '删除用户', '0');
INSERT INTO `sys_permissions` VALUES ('5', 'book:create', '添加书籍', '0');
INSERT INTO `sys_permissions` VALUES ('6', 'book:read', '查询书籍', '0');
INSERT INTO `sys_permissions` VALUES ('7', 'book:update', '修改书籍', '0');
INSERT INTO `sys_permissions` VALUES ('8', 'book:delete', '删除书籍', '0');

-- ----------------------------
-- Table structure for `sys_roles`
-- ----------------------------
DROP TABLE IF EXISTS `sys_roles`;
CREATE TABLE `sys_roles` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `role` varchar(100) DEFAULT NULL COMMENT '角色名',
  `description` varchar(100) DEFAULT NULL COMMENT '描述',
  `available` int(11) DEFAULT NULL COMMENT '是否可用,0表示可用,1表示不可用',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_roles
-- ----------------------------
INSERT INTO `sys_roles` VALUES ('1', 'super_admin', '最高级别的角色', '0');
INSERT INTO `sys_roles` VALUES ('2', 'admin', '普通角色', '0');

-- ----------------------------
-- Table structure for `sys_roles_permissions`
-- ----------------------------
DROP TABLE IF EXISTS `sys_roles_permissions`;
CREATE TABLE `sys_roles_permissions` (
  `role_id` int(10) unsigned NOT NULL COMMENT '角色id',
  `permission_id` int(10) unsigned NOT NULL COMMENT '权限id',
  PRIMARY KEY (`role_id`,`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_roles_permissions
-- ----------------------------
INSERT INTO `sys_roles_permissions` VALUES ('1', '1');
INSERT INTO `sys_roles_permissions` VALUES ('1', '2');
INSERT INTO `sys_roles_permissions` VALUES ('1', '3');
INSERT INTO `sys_roles_permissions` VALUES ('1', '4');
INSERT INTO `sys_roles_permissions` VALUES ('1', '5');
INSERT INTO `sys_roles_permissions` VALUES ('1', '6');
INSERT INTO `sys_roles_permissions` VALUES ('1', '7');
INSERT INTO `sys_roles_permissions` VALUES ('1', '8');

-- ----------------------------
-- Table structure for `sys_users`
-- ----------------------------
DROP TABLE IF EXISTS `sys_users`;
CREATE TABLE `sys_users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` varchar(100) DEFAULT NULL COMMENT '用户名',
  `password` varchar(100) DEFAULT NULL COMMENT '用户名',
  `salt` varchar(100) DEFAULT NULL COMMENT '盐',
  `locked` int(11) DEFAULT NULL COMMENT '是否锁住,0表示未锁,1表示锁住',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_users
-- ----------------------------
INSERT INTO `sys_users` VALUES ('2', 'xl', '23d49e2b98d2a95d82ecd30c0cb5713f', '9ce31fdc59048b65a282a297335acefc', '0');

-- ----------------------------
-- Table structure for `sys_users_roles`
-- ----------------------------
DROP TABLE IF EXISTS `sys_users_roles`;
CREATE TABLE `sys_users_roles` (
  `user_id` int(10) unsigned NOT NULL COMMENT '用户id',
  `role_id` int(10) unsigned NOT NULL COMMENT '角色id',
  PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_users_roles
-- ----------------------------
INSERT INTO `sys_users_roles` VALUES ('2', '1');

 

第三步:pom中导入shiro依赖jar包


    	org.apache.shiro
        shiro-core
        1.2.2
    

    
        org.apache.shiro
        shiro-web
        1.2.2
    

    
        org.apache.shiro
        shiro-ehcache
        1.2.2
    

    
        org.apache.shiro
        shiro-quartz
        1.2.2
    

    
    	org.apache.shiro
        shiro-spring
        1.2.2
    
	
        commons-collections
        commons-collections
        3.2.1
    

 

第四步:拷贝spring-shiro-web.xml到resources目录




    
    
        
    

    
    
        
        
        
        
    

    
    
        
        
        
        
        
        
        
        
        
        
        
        
    

    
    

    
    
        
        
        
        
    
    
        
        
        
        
    

    
    
        
        
        
    
    
      
    	  
	

    
    
        
        
    

    
    
        
        
    

    
    
        
        
        
        
        
        
        
    

    
    
        
        
        
        
    

    
    
        
        
    

     

    
    
        
        
        
        
        	
        		
            	/login.jsp = anon
                /sysUser/doLogin = anon
                /**=user
               
            
        
    

    
    

 

第五步、在web.xml中加入shiro过滤器,并让监听器加载spring-shiro-web.xml,注意下面只是web.xml的部分内容


  
  	shiroFilter
	org.springframework.web.filter.DelegatingFilterProxy
	
		targetFilterLifecycle
		true
	
  
  
	shiroFilter
	/*
  


      
    	contextConfigLocation  
          
        	classpath:spring-mybatis.xml, 
        	
        	classpath:spring-shiro-web.xml
          
     
    
    	org.springframework.web.context.ContextLoaderListener
    

 

第六步、准备登录界面login.jsp

用户名:
密码:
记住我:

 

第七步、SysUserController类

@Controller
@RequestMapping("/sysUser")
public class SysUserController {
	@Resource
	private SysUserService sysUserService;

	public SysUserService getSysUserService() {
		return sysUserService;
	}

	public void setSysUserService(SysUserService sysUserService) {
		this.sysUserService = sysUserService;
	}
	
	@RequestMapping("/doLogin")
	public String doLogin(SysUser sysUser,String rememberMe) {
		System.out.println(rememberMe);
		
		//得到Subject,通过SecurityUtils得到Subject,其会自动绑定到当前线程;如果在web环境在请求结束时需要解除绑定
	    Subject subject = SecurityUtils.getSubject();  
	    //创建用户名/密码身份验证Token(即用户身份/凭证)  
	    UsernamePasswordToken token=new UsernamePasswordToken(sysUser.getUsername(),sysUser.getPassword());  
	    if(rememberMe!=null) {
	    	//当checkbox勾选之后,rememberMe就不为null,此时启用rememberMe
	    	token.setRememberMe(true);
	    }else {
	    	//关闭rememberMe
	    	token.setRememberMe(false);
	    }
	    try {  
	        /*
	         * 身份验证,调用subject.login方法进行登录,其会自动委托给SecurityManager.login方法进行登录
	         * 通过login登录,如果登录失败将抛出相应的AuthenticationException,
	         * 如果登录成功调用subject.isAuthenticated就会返回true,即已经通过身份验证
	         * 如果isRemembered返回true,表示是通过记住我功能登录的而不是调用login方法登录的
	         * isAuthenticated/isRemembered是互斥的,即如果其中一个返回true,另一个返回false
	         */
	        subject.login(token);  
	        
	    } catch (AuthenticationException e) { 
	    	/*
	    	 *  如果身份验证失败请捕获AuthenticationException或其子类,常见的如:
	    	 *  DisabledAccountException(禁用的帐号)、
	    	 *  LockedAccountException(锁定的帐号)、
	    	 *  UnknownAccountException(错误的帐号)、
	    	 *  ExcessiveAttemptsException(登录失败次数过多)、
	    	 *  IncorrectCredentialsException (错误的凭证)、
	    	 *  ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系
	    	 *  对于页面的错误消息展示,最好使用如“用户名/密码错误”而不是“用户名错误”/“密码错误”,防止一些恶意用户非法扫描帐号库
	    	 */
	    	
	        return "login_failed";
	    }  
	    
	    
		return "main";
	}
	
	@ResponseBody
	@RequestMapping("/saveSysUser")
	public String saveSysUser(SysUser sysUser) {
		try {
			//如果b为true,说明添加成功
			boolean b = this.sysUserService.saveSysUser(sysUser);
			return "添加成功";
		} catch (Exception e) {
			//如果有异常,说明添加失败
			return "添加失败";
		}
		
	}
	
	@RequestMapping("/doLogout")
	public String doLogout() {
		//退出操作后一定要重定向页面
		Subject subject = SecurityUtils.getSubject(); 
	    subject.logout();
	    return "login";
	}
	

}

 

第八步、SysUserService接口

public interface SysUserService {
	SysUser getUserByUsername(String username);
	Set listRoles(String username);
	Set listPermissions(String username);
	boolean saveSysUser(SysUser sysUser);
}

 

第九步、SysUserServiceImpl实现类

@Service("sysUserService")
public class SysUserServiceImpl implements SysUserService{
	@Resource
	private SysUserDao sysUserDao;

	public SysUserDao getSysUserDao() {
		return sysUserDao;
	}

	public void setSysUserDao(SysUserDao sysUserDao) {
		this.sysUserDao = sysUserDao;
	}

	@Override
	public SysUser getUserByUsername(String username) {
		return this.sysUserDao.getUserByUsername(username);
	}

	@Override
	public Set listRoles(String username) {
		return this.sysUserDao.listRoles(username);
	}

	@Override
	public Set listPermissions(String username) {
		return this.sysUserDao.listPermissions(username);
	}

	/**
	 * 添加用户
	 */
	@Override
	@Transactional
	public boolean saveSysUser(SysUser sysUser) {
		//service里主要的工作是,将随机salt和加密后的密码存进数据库
		SysUser sysUserToDB = new PasswordHelper().encryptPassword(sysUser);
		//保存最终进入数据库的sysUser
		int rows = this.sysUserDao.saveSysUser(sysUserToDB);
		if(rows==1) {
			return true;
		}else {
			throw new RuntimeException();
		}
	}

	
	
}

 

第十步、SysUserDao接口

public interface SysUserDao {
	SysUser getUserByUsername(String username);
	Set listRoles(String username);
	Set listPermissions(String username);
	int saveSysUser(SysUser sysUser);
}

 

第十一步、SysUser实体类

public class SysUser implements Serializable {
    private int id;
    private String username;
    private String password;
    private String salt;
    private int locked;
   
    public String getCredentialsSalt() {
        return username + salt;
    }

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getSalt() {
		return salt;
	}

	public void setSalt(String salt) {
		this.salt = salt;
	}

	public int getLocked() {
		return locked;
	}

	public void setLocked(int locked) {
		this.locked = locked;
	}

}

 

第十二步、SysUser.xml映射文件

  


	
	
	
	
	
	
	
	
	
	
 	
 	
 	
 		insert into sys_users(username,password,salt,locked) 
 		values(#{username},#{password},#{salt},#{locked})
 	

 

第十三步、UserRealm类,用于获取安全数据源,建议放到util包下

public class UserRealm extends AuthorizingRealm {

    private SysUserService sysUserService;
	
    public SysUserService getSysUserService() {
		return sysUserService;
	}

	public void setSysUserService(SysUserService sysUserService) {
		this.sysUserService = sysUserService;
	}

	/**
	 * 获取权限信息,只有在身份验证成功后才调用此方法获取权限信息
	 */
	@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		//获取用户名
        String username = (String)principals.getPrimaryPrincipal();
        //new一个授权信息
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //给授权信息设置角色集合,只能放角色名
        authorizationInfo.setRoles(sysUserService.listRoles(username));
        //给授权信息设置权限集合
        authorizationInfo.setStringPermissions(sysUserService.listPermissions(username));
        //返回用户授权信息
        return authorizationInfo;
    }

	/**
	 * 获取身份验证信息
	 */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    	
    	//获取用户名
        String username = (String)token.getPrincipal();
        //根据用户名获取User对象
        SysUser user = sysUserService.getUserByUsername(username);

        if(user == null) {
        	//找不到账号
            throw new UnknownAccountException();
        }

        if(user.getLocked()==1) {
        	//帐号锁定
            throw new LockedAccountException();
        }

        /*
         * new一个身份验证信息
         */
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
        		//用户名
                user.getUsername(),
                //从数据库中查出的密文密码
                user.getPassword(),
                //credentialsSalt=username+salt
                ByteSource.Util.bytes(user.getCredentialsSalt()),
                //realm名称
                getName()
        );
        Session session = getSession();
        //将当前用户放进session
        session.setAttribute("username", username);
        /*
         * 返回身份验证信息,将交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
	     * CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配
         */
        return authenticationInfo;
    }
    /**
     * 获取shiro封装的session
     */
    private Session getSession(){  
        try{  
            Subject subject = SecurityUtils.getSubject();  
            Session session = subject.getSession(false);  
            if (session == null){  
                session = subject.getSession();  
            }  
            if (session != null){  
                return session;  
            }  
        }catch (InvalidSessionException e){  
              
        }  
        return null;  
    }  
    //以下是一些清空realm缓存的方法
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }

}

 

第十四步、RetryLimitHashedCredentialsMatcher类,用于验证密码是否正确,建议放到util包下

public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {

    private Cache passwordRetryCache;

    public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
        passwordRetryCache = cacheManager.getCache("passwordRetryCache");
    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
    	//获取用户名
        String username = (String)token.getPrincipal();
        //从缓存中获取该用户已经输入密码的尝试次数
        AtomicInteger retryCount = passwordRetryCache.get(username);
        if(retryCount == null) {
            retryCount = new AtomicInteger(0);
            //将用户输入密码的尝试次数缓存起来
            passwordRetryCache.put(username, retryCount);
        }
        if(retryCount.incrementAndGet() > 5) {
            //密码输入次数超过五次
            throw new ExcessiveAttemptsException();
        }
        /*
         * token是表单上输入的用户名和密码,info是从数据中查的信息,将作密码比对
         */
        boolean matches = super.doCredentialsMatch(token, info);
        if(matches) {
            //清楚尝试次数
            passwordRetryCache.remove(username);
        }
        return matches;
    }
}

 

第十五步、PasswordHelper类,密码帮助类,建议放到util包下

public class PasswordHelper {

    private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
    private String algorithmName = "md5";
    private int hashIterations = 2;

    public void setRandomNumberGenerator(RandomNumberGenerator randomNumberGenerator) {
        this.randomNumberGenerator = randomNumberGenerator;
    }

    public void setAlgorithmName(String algorithmName) {
        this.algorithmName = algorithmName;
    }

    public void setHashIterations(int hashIterations) {
        this.hashIterations = hashIterations;
    }
    
	/**
	 * 加密密码
	 */
    public SysUser encryptPassword(SysUser sysUser) {
    	//设置随机salt
        sysUser.setSalt(randomNumberGenerator.nextBytes().toHex());
        //密码明文+随机salt=密码密文         
        String newPassword = new SimpleHash(
                algorithmName,
                sysUser.getPassword(),
                //credentialsSalt=username+salt
                ByteSource.Util.bytes(sysUser.getCredentialsSalt()),
                hashIterations).toHex();
        //设置密码密文
        sysUser.setPassword(newPassword);
        
        return sysUser;
    }
    
   
}

 

第十六步、准备其他jsp页面

一、main.jsp


	当前用户:
有无超级管理员权限:
有无普通管理员权限:
有哪些权限: 添加用户 查询用户 修改用户 删除用户
退出登录

二、sysuser_add.jsp

用户名: 密码: 是否锁住用户:

三、login_failed.jsp

就显示一句登录失败即可

四、unauthorized.jsp

就显示一句您没有权限即可

 

第十七步、运行测试

登录入口为login.jsp,用户名xl,密码ok,如果登录成功,将跳到main.jsp

你可能感兴趣的:(Spring,shiro,ssm,shiro集成)