一直以来,对于Java开发来说,后台的安全框架,基本就两种,要么用的是shiro来管理,要么就是spring security,自己现在先开始学习shiro,这里就一点一点分享一下自己的学习过程,当然自己现在也是参考网上的相关技术文献,最后还是自己用代码实现一下,这样才能学习认识的更加深刻,废话不说了,过程如下:
1.shiro的身份认证
第一步:收集主体提交的身份和凭证;
我们使用UsernamePasswordToken,支持最常用的用户名/密码认证方式。这是Shiro的org.apache.shiro.authc.AuthenticationToken接口,这是由Shiro的认证系统代表提交的主体和凭证使用的基本接口的实现。username和password就是和Subject认证主体中对应的身份和凭证做验证的。
第二步:提交该身份和凭证;
通过SecurityUtils工具类获取当前执行的用户,然后进行身份认证,参考Subject主体,数据库查询出来的信息。
第三步 :如果提交成功,允许访问,否则重新尝试身份验证或阻止访问;
根据认证的结果来处理正确或者错误的结果,所以我们需要将currentUser.login(token)使用try/catch包起来
第四步:退出
与认证相反的是释放所有已知的确定的状态。当主体完成与应用程序交互,可以调用subject.logout()放弃所有的身份信息,subject.logout()会删除所有身份信息以及他们的会话(这里的会话指的是Shiro中的会话)。
2.shiro的权限认证,即授权
权限认证,也就是访问控制,即在应用中控制谁能访问哪些资源。在权限认证中,最核心的三个要素是:权限,角色和用户:权限(permission):即操作资源的权利,比如访问某个页面,以及对某个模块的数据的添加,修改,删除,查看的权利;
角色(role):指的是用户担任的的角色,一个角色可以有多个权限;
用户(user): 在Shiro 中,代表访问系统的用户,即上一篇博文提到的Subject认证主体。
2.1 基于角色的访问控制
也就是说,授权过程是通过判断角色来完成的,哪个角色可以做这件事,哪些角色可以做这件事等等。它有如下API:
方法 | 作用 |
---|---|
hasRole(String roleName) | 判断是否有该角色访问权,返回boolen |
hasRoles(List<String> roleNames) | 判断是否有这些这些角色访问权,返回boolean[] |
hasAllRoles(Collection<String> roleNames) | 判断是否有这些这些角色访问权,返回boolean |
对这三个API,做一下简单的说明,第一个很简单,传入一个role即可,判断是否拥有该角色访问权,第二个方法是传入一个role的集合,然后Shiro会根据集合中的每一个role做一下判断,并且将每次的判断结果放到boolean[]数组中,顺序与集合中role的顺序一致;第三个方法也是传入一个role的集合,不同的是,返回boolean类型,必须集合中全部role都有才为true,否则为false。
除了这三个API外,Shiro还提供了check的API,与上面不同的是,has-xxx会返回boolean类型的数据,用来判断,而check-xxx不会返回任何东西,如果验证成功就继续处理下面的代码,否则会抛出一个异常,可以用来通过捕获异常来处理。API如下:
方法 | 作用 |
---|---|
checkRole(String roleName) | 如果判断失败抛出AuthorizationException异常 |
checkRoles(String... roleNames) | 如果判断失败抛出AuthorizationException异常 |
checkRoles(Collection<String> roleNames) | 如果判断失败抛出AuthorizationException异常 |
2.2 基于权限的访问控制
基于权限的访问控制和基于角色的访问控制在原理上是一模一样的,只不过API不同而已,我不再做过多的解释,API如下:
方法 | 作用 |
---|---|
isPermitted(String perm) | 判断是否有该权限,返回boolen |
isPermitted(List<String> perms) | 判断是否有这些这些权限,返回boolean[] |
isPermittedAll(Collection<String> perms) | 判断是否有这些这些权限,返回boolean |
checkPermission(String perm) | 如果判断失败抛出AuthorizationException异常 |
checkPermissions(String... perms) | 如果判断失败抛出AuthorizationException异常 |
checkPermissionsAll(Collection<String> perms) | 如果判断失败抛出AuthorizationException异常 |
3.Shiro的内置过滤器(Default Filters)
Shiro中内置的过滤器有以下几个:
过滤器名 | 对应的类 |
---|---|
anon(匿名) | org.apache.shiro.web.filter.authc.AnonymousFilter |
authc(身份验证) | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
authcBasic(http基本验证) | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
logout(退出) | org.apache.shiro.web.filter.authc.LogoutFilter |
noSessionCreation(不创建session) | org.apache.shiro.web.filter.session.NoSessionCreationFilter |
perms(许可验证) | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
port(端口验证) | org.apache.shiro.web.filter.authz.PortFilter |
rest(rest方面) | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
roles(权限验证) | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
ssl(ssl方面) | org.apache.shiro.web.filter.authz.SslFilter |
user(用户方面) | org.apache.shiro.web.filter.authc.UserFilter |
这些内置的过滤器使用方法是这样的,一般先指定一个请求url对应一个过滤器名,由于该过滤器对应一个类,而这个类中会有一个属性,这个属性是当验证失败的时候指定要跳转到那个url的,所以将这个属性配置成验证失败后你要请求的url即可。
我简单说明一下这个配置,比如定义的authc.loginUrl=/login,authc是一个内置过滤器,它对应org.apache.shiro.web.filter.authc.AnonymousFilter类,而这个类中有个loginUrl属性,表示验证失败后将要请求的url映射,这个url映射与一个具体的servlet对应,读到这里,可以和上面的servlet配置对比一下就知道了。roles.unauthorizedUrl也是一样的道理,只不过这里验证失败直接请求一个具体的jsp页面而已。
2.3 url匹配方式
/admin?=authc,表示可以请求以admin开头的字符串,如xxx/adminfefe,但无法匹配多个,即xxx/admindf/admin是不行的
/admin*=authc表示可以匹配零个或者多个字符,如/admin,/admin1,/admin123,但是不能匹配/admin/abc这种
/admin/**=authc表示可以匹配零个或者多个路径,如/admin,/admin/ad/adfdf等。
/admin*/**=authc这个就不多说了,结合上面两个就知道了。