Shiro的第二大功能--授权
什么是授权:
- 授权是什么:在应用中控制谁可以访问哪些资源。
授权内容:主要分为用户,角色,权限。用户可以拥有多个角色,角色也可以对应多个用户,一个角色可以拥有多个权限,一个权限又可以对应多个角色。 - 为什么需要授权:授权是保证软件安全性的重要环节,良好的授权管理能够有效防止未授权访问。
授权框架:Shiro
Shiro 作为一个强大而灵活的安全框架,为我们提供了一种简单而有效的方式来管理应用程序的授权。
Shiro授权流程
- 导入依赖:
<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 或其子类。
- tips:授权认证
1.首先调用Subject.isPermitted/hasRole接口,其会委托SecurityManager。
2.SecurityManager接着会委托给内部组件Authorizer.
3.Realm将用户传入的权限对象与数据库查询出的权限信息进行比较。
4.然后再交回给Autorizer完成鉴权。
- tips:Shiro过滤器
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实现。
授权实现的流程:
- Subject调用isPermitted/hasRoles,或者使用注解@RequestPermissions("user:delete")/@RequiresRoles("shopowner")
- 利用Realm中的doGetAuthorizationInfo去查询数据库或者缓存,获取用户权限。
- 将获取到的数据返回给Authorizer组件,进行权限的验证。
- 返回结果。
过滤器链
Shiro提供了一些默认的过滤器链,常用见有anon,anthc,user,logout。
在某些情况下,默认的过滤器是无法实现特定需求的。
所以需要自定义过滤器。
例如:验证登录anthc,可以继承FormAuthenticationFilter类,重写onAccessDenied方法。