Apache Shiro框架---授权。拿下!

50 阅读3分钟

Shiro的第二大功能--授权

什么是授权:

  1. 授权是什么:在应用中控制谁可以访问哪些资源。
    授权内容:主要分为用户,角色,权限。用户可以拥有多个角色,角色也可以对应多个用户,一个角色可以拥有多个权限,一个权限又可以对应多个角色。
  2. 为什么需要授权:授权是保证软件安全性的重要环节,良好的授权管理能够有效防止未授权访问。

授权框架:Shiro

Shiro 作为一个强大而灵活的安全框架,为我们提供了一种简单而有效的方式来管理应用程序的授权

Shiro授权流程

  1. 导入依赖:
<dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.9.0</version>
  </dependency>
//自定义授权方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("自定义授权");

    //1.创建对象,封装当前登录用户的角色,权限信息
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //1.1获取用户身份信息 -- 获取的用户名
    String principal = principalCollection.getPrimaryPrincipal().toString();
    System.out.println(principal);
    /*TODO:从数据库获取该用户名的角色权限信息
    2.存储角色:错误会报Subject does not have role 异常。
    2.1:一个用户可以有多个角色,一个角色可以有多个权限。
    2.3:角色和权限:在数据库中的对应关系是多对多。
    info.addRole("从数据库获取的角色信息");*/
    //这里为了方便,便固定了,admin:相当是从数据库中获取的
    info.addRole("admin");

    /*TODO:通过角色的信息去获取用户的权限信息(数据库)
    获取之后封装都对象中去,这里为了方便,便固定了 */
    List<String> permissions = new ArrayList<>();
    Collections.addAll(permissions,"user:insert","user:delete","user:update","user:select");
    //permissions:相当于从数据库中获取的权限信息
    info.addStringPermissions(permissions);
    //返回信息,返回之后,Shiro会利用Authorizer组件去判断授权信息。
    return info;
}

2. tips: 身份认证
1.SecurityManager权限验证工厂, 一个全局唯一的安全管理器 。
2.SecurityUtils可以通过这个工具类获取全局的SecurityManager 但是需要我们首先设置一下。
3.Subject我们当前登录的账号(用户),通过isAuthenticated方法知道是否登录了.
4.UsernamePasswordToken是登录的凭证,用户输入的账号密码放进去,让subject判断是否登录成功。
5.login登录的时候通过异常判断是哪种登录失败。
6.如果身份验证失败请捕获 AuthenticationException 或其子类。

  1. tips:授权认证
    1.首先调用Subject.isPermitted/hasRole接口,其会委托SecurityManager。
    2.SecurityManager接着会委托给内部组件Authorizer.
    3.Realm将用户传入的权限对象与数据库查询出的权限信息进行比较。
    4.然后再交回给Autorizer完成鉴权。

image.png

  1. tips:Shiro过滤器 image.png anon:任何人都能访问。
    anthc:需要登录才能访问,但不包含rememberMe。
    user:需要登录才能访问,包含rememberMe。
    logout;退出过滤器。

自定义过滤器:
在前后端分离的场景,Shiro默认的过滤器就无法满足了,因为Shiro两个默认认证过滤器authc和user过滤器,访问时会去项目的当前目录下找login.jsp文件,而前后端分离是需要,后端传json数据给前端即可。 1.搜索DefaultFilter,找到authc过滤器实现类FormAuthenticationFilter ,发现其验证方法是onAccessDenied方法。
重写方法:

//自定义的登录过滤器
public class MyFormAuthenticationFilter extends UserFilter {
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse resp = (HttpServletResponse) response;
        resp.setContentType("application/json; charset=utf-8");
        Map<String,String> map = new HashMap<>();
        map.put("code",HttpStatus.FORBIDDEN.toString());
        map.put("msg","未登录");
        ...
        return false;
    }
}

总结:

Shiro除了认证功能,还具备授权功能。授权主要是利用SecurityManager中的Authorizer实现。

授权实现的流程:

  1. Subject调用isPermitted/hasRoles,或者使用注解@RequestPermissions("user:delete")/@RequiresRoles("shopowner")
  2. 利用Realm中的doGetAuthorizationInfo去查询数据库或者缓存,获取用户权限。
  3. 将获取到的数据返回给Authorizer组件,进行权限的验证。
  4. 返回结果。

过滤器链

Shiro提供了一些默认的过滤器链,常用见有anon,anthc,user,logout。
在某些情况下,默认的过滤器是无法实现特定需求的。 所以需要自定义过滤器。 例如:验证登录anthc,可以继承FormAuthenticationFilter类,重写onAccessDenied方法。