发表于: 2017-08-11 22:59:38

1 935


今天完成的事情:编译shiro核心代码,具体整个目录会在接下的总结日报中放出。

shiroConfig

@Configuration
public class ShiroConfig {

@Autowired(required = false)
SysPermissionInitService sysPermissionInitService;

   @Value("${spring.redis.host}")
   private String host;

   @Value("${spring.redis.port}")
   private int port;

   @Value("${spring.redis.timeout}")
   private int timeout;

   /**
    * ShiroFilterFactoryBean 处理拦截资源文件问题。
    * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
    * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
    *
    * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
    * 3、部分过滤器可指定参数,如perms,roles
    *
    */
   @Bean
   public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
   ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

       // 必须设置 SecurityManager
       shiroFilterFactoryBean.setSecurityManager(securityManager);
       // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
       shiroFilterFactoryBean.setLoginUrl("/login");
       // 登录成功后要跳转的链接
       shiroFilterFactoryBean.setSuccessUrl("/index");
       // 未授权界面;
       shiroFilterFactoryBean.setUnauthorizedUrl("/403");
       //自定义拦截器
       Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
       //限制同一帐号同时在线的个数。
       filtersMap.put("kickout", kickoutSessionControlFilter());
       shiroFilterFactoryBean.setFilters(filtersMap);
       // 权限控制map.
       Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
       // 配置不会被拦截的链接 顺序判断
       // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
       // 从数据库获取动态的权限
       // filterChainDefinitionMap.put("/add", "perms[权限添加]");
       // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
       // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
       //logout这个拦截器是shiro已经实现好了的。
       // 从数据库获取
       List<SysPermissionInit> list = sysPermissionInitService.selectAll();

       for (SysPermissionInit sysPermissionInit : list) {
          filterChainDefinitionMap.put(sysPermissionInit.getUrl(),
                   sysPermissionInit.getPermissionInit());
       }

       shiroFilterFactoryBean
       .setFilterChainDefinitionMap(filterChainDefinitionMap);
       return shiroFilterFactoryBean;
   }

   @Bean
   public SecurityManager securityManager() {
   DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
       // 设置realm.

       securityManager.setRealm(myShiroRealm());
       // 自定义缓存实现 使用redis

       securityManager.setCacheManager(cacheManager());
       // 自定义session管理 使用redis

       securityManager.setSessionManager(sessionManager());
       //注入记住我管理器;

       securityManager.setRememberMeManager(rememberMeManager());
       return securityManager;
   }

   /**
    * 身份认证realm; (这个需要自己写,账号密码校验;权限等)
    *
    * @return
    */
   @Bean
   public MyShiroRealm myShiroRealm() {
   MyShiroRealm myShiroRealm = new MyShiroRealm();
       return myShiroRealm;
   }

    /**
    * 配置shiro redisManager
    * 使用的是shiro-redis开源插件
    * @return
    */
   public RedisManager redisManager() {
       RedisManager redisManager = new RedisManager();
       redisManager.setHost(host);
       redisManager.setPort(port);
       redisManager.setExpire(1800);// 配置缓存过期时间
       redisManager.setTimeout(timeout);
       // redisManager.setPassword(password);
       return redisManager;
   }

   /**
    * cacheManager 缓存 redis实现
    * 使用的是shiro-redis开源插件
    * @return
    */
   public RedisCacheManager cacheManager() {
       RedisCacheManager redisCacheManager = new RedisCacheManager();
       redisCacheManager.setRedisManager(redisManager());
       return redisCacheManager;
   }
   /**
    * RedisSessionDAO shiro sessionDao层的实现 通过redis
    * 使用的是shiro-redis开源插件
    */
   @Bean
   public RedisSessionDAO redisSessionDAO() {
       RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
       redisSessionDAO.setRedisManager(redisManager());
       return redisSessionDAO;
   }

   /**
    * Session Manager
    * 使用的是shiro-redis开源插件
    */
   @Bean
   public DefaultWebSessionManager sessionManager() {
       DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
       sessionManager.setSessionDAO(redisSessionDAO());
       return sessionManager;
   }

   /**
    * cookie对象;
    * @return
    */
   public SimpleCookie rememberMeCookie(){
       //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
       SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
       //<!-- 记住我cookie生效时间30天 ,单位秒;-->
       simpleCookie.setMaxAge(2592000);
       return simpleCookie;
   }

   /**
    * cookie管理对象;记住我功能
    * @return
    */
   public CookieRememberMeManager rememberMeManager(){
       CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
       cookieRememberMeManager.setCookie(rememberMeCookie());
       //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
       cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
       return cookieRememberMeManager;
   }

   /**
    * 限制同一账号登录同时登录人数控制
    * @return
    */
   public KickoutSessionControlFilter kickoutSessionControlFilter(){
       KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
       //使用cacheManager获取相应的cache来缓存用户登录的会话;用于保存用户—会话之间的关系的;

       //这里我们还是用之前shiro使用的redisManager()实现的cacheManager()缓存管理

       //也可以重新另写一个,重新配置缓存时间之类的自定义缓存属性
       kickoutSessionControlFilter.setCacheManager(cacheManager());
       //用于根据会话ID,获取会话进行踢出操作的;
       kickoutSessionControlFilter.setSessionManager(sessionManager());
       //是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户;踢出顺序。

       kickoutSessionControlFilter.setKickoutAfter(false);
       //同一个用户最大的会话数,默认1;比如2的意思是同一个用户允许最多同时两个人登录;

       kickoutSessionControlFilter.setMaxSession(1);
       //被踢出后重定向到的地址;

       kickoutSessionControlFilter.setKickoutUrl("/kickout");
       return kickoutSessionControlFilter;
   }
}

MyShiroRealm

public class MyShiroRealm extends AuthorizingRealm {

@Autowired
private SysUserService sysUserService;

   @Autowired
private SysPermissionService sysPermissionService;

   @Autowired
StringRedisTemplate stringRedisTemplate;

   @Autowired
private SysRoleService sysRoleService;

   //用户登录次数计数  redisKey 前缀

   private String SHIRO_LOGIN_COUNT = "shiro_login_count_";

   //用户登录是否被锁定    一小时 redisKey 前缀

   private String SHIRO_IS_LOCK = "shiro_is_lock_";

   /**

    * 认证信息.(身份验证) : Authentication 是用来验证用户身份

    *

    * @param token

    * @return

    * @throws AuthenticationException

    */
   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(
       AuthenticationToken authcToken) throws AuthenticationException {
       UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
       String name = token.getUsername();
       String password = String.valueOf(token.getPassword());
       //访问一次,计数一次

       ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
       opsForValue.increment(SHIRO_LOGIN_COUNT+name, 1);
       //计数大于5时,设置用户被锁定一小时

       if(Integer.parseInt(opsForValue.get(SHIRO_LOGIN_COUNT+name))>=5){
           opsForValue.set(SHIRO_IS_LOCK+name, "LOCK");
           stringRedisTemplate.expire(SHIRO_IS_LOCK+name, 1, TimeUnit.HOURS);
       }
       if ("LOCK".equals(opsForValue.get(SHIRO_IS_LOCK+name))){
       throw new DisabledAccountException("由于密码输入错误次数大于5次,帐号已经禁止登录!");
       }
       Map<String, Object> map = new HashMap<String, Object>();
       map.put("nickname", name);
       //密码进行加密处理  明文为  password+name

       String paw = password+name;
       String pawDES = MyDES.encryptBasedDes(paw);
       map.put("pswd", pawDES);
       SysUser user = null;
       // 从数据库获取对应用户名密码的用户

       List<SysUser> userList = sysUserService.selectByMap(map);
       if(userList.size()!=0){
          user = userList.get(0);
       }
       if (null == user) {
       throw new AccountException("帐号或密码不正确!");
       }else if("0".equals(user.getStatus())){
           /**
            * 如果用户的status为禁用。那么就抛出<code>DisabledAccountException</code>
            */
           throw new DisabledAccountException("此帐号已经设置为禁止登录!");
       }else{
           //登录成功

           //更新登录时间 last login time

           user.setLastLoginTime(new Date());
           sysUserService.updateById(user);
           //清空登录计数

           opsForValue.set(SHIRO_LOGIN_COUNT+name, "0");
       }
       Logger.getLogger(getClass()).info("身份认证成功,登录用户:"+name);
       return new SimpleAuthenticationInfo(user, password, getName());
   }

   /**
    * 授权
    */
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(
       PrincipalCollection principals) {
       System.out.println("权限认证方法:MyShiroRealm.doGetAuthorizationInfo()");
       SysUser user = (SysUser)SecurityUtils.getSubject().getPrincipal();
       String userId = user.getId();
       SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
       //根据用户ID查询角色(role),放入到Authorization里。

     Map<String, Object> map = new HashMap<String, Object>();

     map.put("user_id", userId);

     List<SysRole> roleList = sysRoleService.selectByMap(map);

     Set<String> roleSet = new HashSet<String>();

     for(SysRole role : roleList){

     roleSet.add(role.getType());

     }
     Set<String> roleSet = new HashSet<String>();
       roleSet.add("100002");
       info.setRoles(roleSet);
       //根据用户ID查询权限(permission),放入到Authorization里。

     List<SysPermission> permissionList = sysPermissionService.selectByMap(map);

     Set<String> permissionSet = new HashSet<String>();

     for(SysPermission Permission : permissionList){

     permissionSet.add(Permission.getName());
     }
     Set<String> permissionSet = new HashSet<String>();
       permissionSet.add("权限添加");
       permissionSet.add("权限删除");
       info.setStringPermissions(permissionSet);
       return info;
   }
}

明天计划的事情:继续编译

遇到的问题:对shiro的角色控制还不是很熟

收获:学习shiro










返回列表 返回列表
评论

    分享到