大师系列-Springboot集成Shiro配置精通

Shiro是大家使用来进行后台权限配置的一个框架,通过本文你可以轻松配置Shiro,并完成多Realm的接入,多种授权方式,并解决很多Shiro框架本身带来的隐藏问题。我相信大家看完这篇文章,都可以很快精通Shiro并进行配置操作。引入基本的框架包 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-start
摘要由CSDN通过智能技术生成

Shiro是大家使用来进行后台权限配置的一个框架,通过本文你可以轻松配置Shiro,并完成多Realm的接入,多种授权方式,并解决很多Shiro框架本身带来的隐藏问题。

我相信大家看完这篇文章,都可以很快精通Shiro并进行配置操作。

引入基本的框架包

 <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring-boot-web-starter</artifactId>
 </dependency>

 <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-redis</artifactId>
 </dependency>

首先定义错误的依赖项,未授权,未鉴权这两个状态需要进行区分

/**
 * 授权异常定义.
 *
 * @author ucucs.
 */
public enum AuthErrorType implements ErrorType {
  AUTH_ERROR("4400", "授权出现异常"),

  /** 未授权错误. */
  UNAUTHORIZED("4401", "未授权错误"),

  /** 未登录错误. */
  UNAUTHENTICATED("4402", "未登录错误");

  /** 错误代码. */
  private final String code;

  /** 错误提示. */
  private final String msg;

  AuthErrorType(String code, String msg) {
    this.code = code;
    this.msg = msg;
  }

  @Override
  public String getCode() {
    return code;
  }

  @Override
  public String getMsg() {
    return msg;
  }
}

需要定义通用的Filter,进行统一的鉴权管理

public class ShiroAuthorizationFilter extends AuthorizationFilter {

  protected Function<Subject, Boolean> checkExtraAccessFunc = null;

  public ShiroAuthorizationFilter() {
    this.checkExtraAccessFunc = subject -> subject.hasRole(RoleType.SUPER_ADMIN);
  }

  public ShiroAuthorizationFilter(Function<Subject, Boolean> extraAccessFunc) {
    this.checkExtraAccessFunc = extraAccessFunc;
  }

  @Override
  protected boolean isAccessAllowed(
      ServletRequest request, ServletResponse response, Object mappedValue) {
    Subject subject = getSubject(request, response);

    HttpServletRequest servletRequest = (HttpServletRequest) request;
    String servletPath = servletRequest.getServletPath();

    if (!subject.isAuthenticated()) {
      subject.logout();
      return false;
    }

    if (checkExtraAccessFunc != null) {
      boolean extraAccess = checkExtraAccessFunc.apply(subject);
      if (extraAccess) {
        return true;
      }
    }

    return subject.isPermitted(servletPath);
  }

  @Override
  protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
      throws IOException {
    // 重写该方法主要是避免302跳转
    Subject subject = getSubject(request, response);

    HttpServletResponse resp = (HttpServletResponse) response;

    resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
    resp.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

    ErrorType errorType =
        subject.isAuthenticated() ? AuthErrorType.UNAUTHORIZED : AuthErrorType.UNAUTHENTICATED;
    Result<?> message = Result.fail(errorType);
    resp.getWriter().write(JsonUtil.toJson(message));
    return false;
  }
}

多Realm的情况下,Shiro自身的框架判断,是需要两个Realm都鉴权成功,满足资源配置要求,才代表通过。

但很多时候,不同的登录方式,可能要求的是独立的鉴权模式,所以我们需要重写Shiro多Realm下的鉴权判断方法,只要有一个成功即可

public class ShiroModularRealmAuthorizer extends ModularRealmAuthorizer {

  public ShiroModularRealmAuthorizer() {}

  public ShiroModularRealmAuthorizer(Collection<Realm> realms) {
    super(realms);
  }

  @Override
  public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
    for (Realm realm : this.getRealms()) {
      if ((realm instanceof Authorizer)
          && ((Authorizer) realm).hasRole(principals, roleIdentifier)) {
        return true;
      }
    }

    return false;
  }

  @Override
  public boolean isPermitted(PrincipalCollection principals, String permission) {
    for (Realm realm : this.getRealms()) {
      if ((realm instanceof Authorizer)
          && ((Authorizer) realm).isPermitted(principals, permission)) {
        return true;
      }
    }

    return false;
  }
}

重新定义一个通用的Shiro资源加载的接口,方便额外实现加载角色和权限

public interface ShiroPermissionService {

   Set<String> getPermissionsByRole(String corpId, String userId);

   Set<String> getRoleByUserName(String corpId, String userId);

}

最后,肯定离不开缓存,缓存是可以自定义的,我们采用Redis

public class ShiroRedisCache<K, V> implements Cache<K, V> {

  private static final Logger logger = LoggerFactory.getLogger(ShiroRedisCache.class);

  protected final RedisTemplate<String, Object> redisTemplate;
  protected final String keyPrefix;
  protected final int expireSecond;

  public ShiroRedisCache(
      RedisTemplate<String, Object> redisTemplate, String prefix, int expireSecond) {
    this.redisTemplate = redisTemplate;
    this.keyPrefix = prefix;
    this.expireSecond = expireSecond;
  }

  /**
   * get shiro authorization redis key-value
   *
   * @param key key
   * @return value
   * @throws CacheException get cache exception
   */
  @SuppressWarnings("unchecked")
  @Override
  public V get(K key) throws CacheException {
    if (key == null) {
      return nul
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值