shiro

shiro开发

shiro源码解读

shiro默认拦截器

anon(AnonymousFilter.class),
authc(FormAuthenticationFilter.class),
authcBasic(BasicHttpAuthenticationFilter.class),
logout(LogoutFilter.class),
noSessionCreation(NoSessionCreationFilter.class),
perms(PermissionsAuthorizationFilter.class),
port(PortFilter.class),
rest(HttpMethodPermissionFilter.class),
roles(RolesAuthorizationFilter.class),
ssl(SslFilter.class),
user(UserFilter.class);
复制代码

createFilterChainManager

  • 对每一个默认的过滤器调用applyGlobalPropertiesIfNecessary进行设置
  • 对每一个自定义的过滤器进行设置并添加到过滤器管理器DefaultFilterChainManager中
  • 第三是调用createChain构造chain(过滤器链:记录一个url和过滤器之间一对多的关系)

shiro知识总结

为什么选择shiro

  • 从外部来看:具有非常简单易于使用的API
  • 从内部来看:有一个可扩展的架构

shiro提供了哪些功能

  • 认证Authentication:身份认证/登录
  • 授权Authorization:即权限验证
  • 加密Cryptography:保护数据的安全性
  • 会话管理Session Manager:用户登是一次会话
  • Web集成Web Support:非常容易的集成到Web环境
  • 缓存Caching:用户登录后,其用户信息、拥有的角色/权限缓存
  • 匿名Run As:允许一个用户假装为另一个用户
  • 记住我Remember Me:一次登录后再次访问不用登录

shiro常见名词

  1. Subject:主体,可以是任何可以与应用交互的“用户”;
  2. SecurityManager:相当于SpringMVC中的DispatcherServlet,所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理;
  3. Authenticator:认证器,负责主体认证的
  4. Authrizer:授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;
  5. Realm:可以有1个或多个Realm,可以认为是安全实体数据源;
  6. SessionManager:Shiro抽象了一个自己的Session来管理主体与应用之间交互的数据;
  7. CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;
  8. Cryptography:密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密的。

shiro 原理简介

身份认证步骤

  1. 传入用户的身份(用户名<唯一标识>)和凭证(密码):UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
  2. 调用Subject.login(token)进行登录
  3. 自动委托给Security Manager
  4. 委托给Authenticator进行身份验证
  5. (传入凭证信息)委托给相应的AuthenticationStrategy进行多Realm(数据源)身份验证

身份认证实现

1.继承AuthorizingRealm(授权)即可;其继承了AuthenticatingRealm(即身份验证),而且也间接继承了CachingRealm(带有缓存实现)(注:也可以直接implements Realm)

身份鉴权实现

shiro开发实现

  • 1 继承extends AuthorizingRealm提供安全数据源
      /**
           * @Title
           * @Description
           * @param principalCollection
           * @return org.apache.shiro.authz.AuthorizationInfo
           * @date  2017/8/8 下午1:36
           * @author tush
           */
          @Override
          protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
              SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
              //得到用户身份信息
              String username = principalCollection.getPrimaryPrincipal().toString();
              //得到用户权限信息
              ShiroUserRolePermission shiroUserRolePermission = null;
              try {
                  shiroUserRolePermission = provideUserRolePermissionInfo(username);
              } catch (PendingException e) {
                  ShiroLogger.info("shiro get redis cache catch a exception ....",e);
              }
              //获取的用户信息为空 可能出现异常
              if (shiroUserRolePermission != null){
                  Set<String> roleSet = shiroUserRolePermission.getRoleSet();
                  //得到用户的权限列表
                  Set<ShiroPermission> permissionList = shiroUserRolePermission.getPermissionSet();
                  Set<Permission> bitPermissions = new HashSet<>();
                  //得到权限实例
                  permissionList.forEach(permission -> {
                      ShiroPermission param = new ShiroPermission().builder()
                              .actionUrl(permission.getActionUrl())
                              .permissionCode(permission.getPermissionCode())
                              .instanceId(permission.getInstanceId())
                              .build();
                      bitPermissions.add(new DefinitionBitPermission(JackSonUtils.bean2Json(param)));
                  });
                  if (null != bitPermissions) {
                      ShiroLogger.info("成功获取{}用户权限信息",username);
                      authorizationInfo.addObjectPermissions(bitPermissions);
                  }
                  if (null != roleSet) {
                      ShiroLogger.info("成功获取{}用户角色信息",username);
                      authorizationInfo.addRoles(roleSet);
                  }
      
              }
      
              return authorizationInfo;
          }
      
      /**
           * @Title
           * @Description  登录认证
           * @param authenticationToken 身份token
           * @return org.apache.shiro.authc.AuthenticationInfo
           * @date  2017/8/16 上午10:21
           * @author tush
           */
          @Override
          protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
              //用户唯一标识
              String username = authenticationToken.getPrincipal().toString();
              //用户信息
      //        ShiroUser user = null;
      //        try {
      //            user = provideUserRolePermissionInfo(username).getUser();
      //        } catch (PendingException e) {
      //            ShiroLogger.error("shiro get redis cache catch a exception ....",e);
      //        }
      //        if (user == null){
      //            throw new UnknownAccountException();
      //        }
               String password = new String((char[])authenticationToken.getCredentials());
      //        if (!password.equals(user.getPassword())) {
      //            throw new UnknownAccountException();
      //        }
              SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,password,getName());
              return info;
          }
      
复制代码
  • 权限比较实体转换器
      public class BitAndWildPermissionResolver implements PermissionResolver {
      
          private static final String JSON_START = "{";
          private static final String JSON_END = "}";
      
          /**
           * @Title
           * @Description  Json权限准换成权限元数据
           * @param permissionStr
           * @return org.apache.shiro.authz.Permission
           * @date  2017/8/16 上午10:20
           * @author tush
           */
          @Override
          public Permission resolvePermission(String permissionStr) {
              //拦截器传入的json对象转换成permission元数据
              if (permissionStr.startsWith(JSON_START)&&permissionStr.endsWith(JSON_END)) {
                  return new DefinitionBitPermission(permissionStr);
              }
              return new WildcardPermission(permissionStr);
          }
      }
复制代码
  • 自定义权限比较实体对象
      public class DefinitionBitPermission implements Permission,Serializable{
         /**
           * @Title
           * @Description 权限比较方法
           * @param permission
           * @return boolean
           * @date  2017/8/8 11:29
           * @author tush
           */
          @Override
          public boolean implies(Permission permission) {
              if(!(permission instanceof DefinitionBitPermission)) {
                  return false;
              }
              DefinitionBitPermission bitPermission = (DefinitionBitPermission)permission;
              if (bitPermission.param.getPermissionCode()>15) {
                  return false;
              }
              if(!(DEFAULT_PERMISSION.equals(this.param.getActionUrl()) || this.param.getActionUrl().equals(bitPermission.param.getActionUrl()))) {
                  return false;
              }
              if(this.param.getPermissionCode() == 0 || (this.param.getPermissionCode() & bitPermission.param.getPermissionCode()) == 0) {
                  return false;
              }
              if(!(DEFAULT_PERMISSION.equals(this.param.getInstanceId()) || this.param.getInstanceId().equals(bitPermission.param.getInstanceId()))) {
                  return false;
              }
              return true;
          }
      }
复制代码
  • 自定义拦截器
       class DefinitionAccessControlFilter extends AccessControlFilter {
             /**
           * @Title
           * @Description 鉴权
           * @param servletRequest
           * @param servletResponse
           * @param o
           * @return boolean
           * @date  2017/8/8 上午11:09
           * @author tush
           */
          @Override
          protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
              //获取实体
              ShiroLogger.info("shiro 权限检查开始....");
              Subject subject = getSubject(servletRequest,servletResponse);
              if (subject.getPrincipal()==null ){
                  return false;
              }
              //超级管理员权限处理
              if (subject.getSession().getAttribute(ADM_FLAG) != null){
                  Object obj = subject.getSession().getAttribute(ADM_FLAG);
                  if (obj instanceof Integer) {
                      if (IS_ADM_STRING == obj) {
                          return true;
                      }
                  }else if (obj instanceof String){
                      if (IS_ADM_STRING.equals(obj)) {
                          return true;
                      }
                  }
              }
              //得到请求地址
              String url = getPathWithinApplication(servletRequest);
              //得到请求方法
              String method = ((HttpServletRequest) servletRequest).getMethod();
              //权限参数初始化
              ShiroPermission param = new ShiroPermission();
              //将方法标识转换成权限位
              if (method.equals(SHIRO_GET)) {
                  param.setPermissionCode(BINARY_EIGHT);
              } else if (method.equals(SHIRO_POST)){
                  param.setPermissionCode(BINARY_FOUR);
              } else if (method.equals(SHIRO_PUT)) {
                  param.setPermissionCode(BINARY_TWO);
              } else {
                  param.setPermissionCode(BINARY_ONE);
              }
              //设置请求地址
              param.setActionUrl(url);
              //设置实例名称:默认全部实例
              //param.setInstanceId("*");
              //开始鉴权
              return subject.isPermitted(new DefinitionBitPermission(JackSonUtils.bean2Json(param)));
          }
       }
复制代码
  • 自定义权限注解
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.METHOD})//适用的地方:方法上
      public @interface CheckPermission {
          /** 权限地址 **/
          @NotNull
          String actionUrl();
      
      
          /** 权限位 **/
          PermissionMethod permissionCode() default PermissionMethod.GET;//默认没有任何权限
      
          /** 权限实例 **/
          String instanceId() default "*";//默认全部实例
      
      }
复制代码
  • 权限注解过滤器实现
      @Aspect
      @Component
      public class ExtPermissionInterceptor {
      
          private static final String DEFAULT_PERMISSION = "*";
          /**
           * @Title
           * @Description 权限检查实体注解
           * @param pjp
           * @param checkPermission
           * @return java.lang.Object
           * @date  2017/8/16 上午9:54
           * @author tush
           */
          @Around("@annotation(checkPermission)")
          public Object doInterceptor(ProceedingJoinPoint pjp, CheckPermission checkPermission) throws Throwable {
              boolean isPermission = false;
              Subject subject = SecurityUtils.getSubject();
              if (subject==null||subject.getPrincipal()==null){
                  ShiroLogger.info("ExtPermissionInterceptor say:you have no login");
                  throw new UnknownAccountException("session 失效");
              }
              //没有获得注解  及不需要权限-- 则直接运行
              if (null != checkPermission) {
                  String actionUrl = checkPermission.actionUrl();
                  PermissionMethod method = checkPermission.permissionCode();
                  int permissionCode = method.getValue();
                  String instanceId = checkPermission.instanceId();
                  ShiroPermission permission = new ShiroPermission();
                  permission.setActionUrl(actionUrl);
                  permission.setPermissionCode(permissionCode);
                  permission.setInstanceId(StringUtil.isNotEmpty(instanceId)?instanceId:DEFAULT_PERMISSION);
                  //当前登录人 具有权限
                  if (subject.isPermitted(new DefinitionBitPermission(JackSonUtils.bean2Json(permission)))) {
                      isPermission = true;
                  }
              } else {
                  isPermission = true;
              }
              if (isPermission) {
                  //有执行方法或权限不拦截
                  ShiroLogger.info("annotation checkPermission grant permission");
                  return pjp.proceed();
              } else {
                  ShiroLogger.info("you have no permission....");
                  throw new UnauthorizedException("没有访问权限");
              }
          }
      }
复制代码
  • cache 实现
      public class CustomShiroCacheManager implements CacheManager, Destroyable {
      
          private ShiroCacheManager shiroCacheManager;
          @Override
          public <K, V> Cache<K, V> getCache(String name) throws CacheException {
              return getShiroCacheManager().getCache(name);
          }
          @Override
          public void destroy() throws Exception {
              shiroCacheManager.destroy();
          }
      
          public ShiroCacheManager getShiroCacheManager() {
              return shiroCacheManager;
          }
      
          public void setShiroCacheManager(ShiroCacheManager shiroCacheManager) {
              this.shiroCacheManager = shiroCacheManager;
          }
      
      }
复制代码
  • shiro 配置文件(交由spring管理)
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
          ">
      
          <!-- 保证实现了Shiro内部lifecycle函数的bean执行   -->
          <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
          <!-- 开启Shiro注解 -->
          <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
          <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
              <property name="securityManager" ref="securityManager"/>
          </bean>
      
          <!-- 用户缓存 -->
          <bean id="cacheManager" class="com.weiyi.pay.framework.shiro.cache.jedis.CustomShiroCacheManager">
              <property name="shiroCacheManager" ref="definitionShiroCacheManager"/>
          </bean>
      
          <!-- shiro 缓存实现,对ShiroCacheManager,采用redis的实现 -->
          <bean id="definitionShiroCacheManager" class="com.weiyi.pay.framework.shiro.cache.impl.DefinitionShiroCacheManager">
              <property name="jedisManager" ref="jedisManager"/>
          </bean>
      
          <!-- redis 的缓存 -->
          <bean id="jedisManager" class="com.weiyi.pay.framework.shiro.cache.jedis.JedisManager"/>
      
          <!-- 自定义Realm -->
          <bean id="weDefinitionAuthorizingRealm" class="com.weiyi.pay.framework.shiro.realm.WeDefinitionAuthorizingRealm">
              <property name="authorizationCachingEnabled" value="true"/>
          </bean>
      
          <!-- 安全管理器 -->
          <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
              <property name="realm" ref="weDefinitionAuthorizingRealm"/>
              <!-- 注入缓存管理器 -->
              <property name="cacheManager" ref="cacheManager"/>
          </bean>
      
          <!--自定义登录状态检查 -->
          <bean id="loginAuthc" class="com.weiyi.pay.framework.shiro.filter.DefinitionAuthenticationFilter"/>
          <!--自定义二进制鉴权 -->
          <bean id="biteAuthc" class="com.weiyi.pay.framework.shiro.filter.DefinitionAccessControlFilter"/>
      
          <bean id="anonAuthc" class="com.weiyi.pay.framework.shiro.filter.DefinitionAnonymousFilter"/>
      </beans>
      
复制代码
  • session实现

    集成springs-session

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值