目录
权限角色控制 @RequiresRoles, @RequiresPermissions等注解的使用和编程式控制
-
步骤:
- 创建一个类 ,继承AuthorizingRealm->AuthenticatingRealm->CachingRealm->Realm
- 重写授权方法 doGetAuthorizationInfo
- 重写认证方法 doGetAuthenticationInfo
-
方法:
- 当用户登陆的时候会调用 doGetAuthenticationInfo
- 进行权限校验的时候会调用: doGetAuthorizationInfo
-
对象介绍
-
UsernamePasswordToken : 对应就是 shiro的token中有Principal和Credential
- UsernamePasswordToken-》HostAuthenticationToken-》AuthenticationToken
-
SimpleAuthorizationInfo:代表用户角色权限信息
-
SimpleAuthenticationInfo :代表该用户的认证信息
-
hiro认证和授权流程的源码解读,和断点测试
认证流程解读:subject.login(usernamePasswordToken);
DelegatingSubject->login()
DefaultSecurityManager->login()
AuthenticatingSecurityManager->authenticate()
AbstractAuthenticator->authenticate()
ModularRealmAuthenticator->doAuthenticate()
ModularRealmAuthenticator->doSingleRealmAuthentication()
AuthenticatingRealm->getAuthenticationInfo()
补充:有些同学找不到密码验证方法 AuthenticatingRealm-> assertCredentialsMatch()
授权流程解读:subject.checkRole("admin")
DelegatingSubject->checkRole()
AuthorizingSecurityManager->checkRole()
ModularRealmAuthorizer->checkRole()
AuthorizingRealm->hasRole()
AuthorizingRealm->doGetAuthorizationInfo()
Shiro内置的Filter过滤器
成功:跳转到target
失败:到认证页面
-
核心过滤器类:DefaultFilter, 配置哪个路径对应哪个拦截器进行处理
-
authc:org.apache.shiro.web.filter.authc.FormAuthenticationFilter
- 需要认证登录才能访问
-
user:org.apache.shiro.web.filter.authc.UserFilter
- 用户拦截器,表示必须存在用户。
-
anon:org.apache.shiro.web.filter.authc.AnonymousFilter
- 匿名拦截器,不需要登录即可访问的资源,匿名用户或游客,一般用于过滤静态资源。
-
roles:org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
- 角色授权拦截器,验证用户是或否拥有角色。
- 参数可写多个,表示某些角色才能通过,多个参数时写 roles["admin,user"],当有多个参数时必须每个参数都通过才算通过
-
perms:org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
- 权限授权拦截器,验证用户是否拥有权限
- 参数可写多个,表示需要某些权限才能通过,多个参数时写 perms["user, admin"],当有多个参数时必须每个参数都通过才算可以
-
authcBasic:org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
- httpBasic 身份验证拦截器。
-
logout:org.apache.shiro.web.filter.authc.LogoutFilter
- 退出拦截器,执行后会直接跳转到
shiroFilterFactoryBean.setLoginUrl();
设置的 url
- 退出拦截器,执行后会直接跳转到
-
port:org.apache.shiro.web.filter.authz.PortFilter
- 端口拦截器, 可通过的端口。
-
ssl:org.apache.shiro.web.filter.authz.SslFilter
- ssl拦截器,只有请求协议是https才能通过。
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);
配置路径:
-
/admin/video /user /pub
-
路径通配符支持 ?、、*,注意通配符匹配不 包括目录分隔符“/”
-
心 可以匹配所有,不加*可以进行前缀匹配,但多个冒号就需要多个 * 来匹配
URL权限采取第一次匹配优先的方式
? : 匹配一个字符,如 /user? , 匹配 /user3,但不匹配/user/;
* : 匹配零个或多个字符串,如 /add* ,匹配 /addtest,但不匹配 /user/1
** : 匹配路径中的零个或多个路径,如 /user/** 将匹 配 /user/xxx 或 /user/xxx/yyy
例子
/user/**=filter1
/user/add=filter2
请求 /user/add 命中的是filter1拦截器
- 性能问题:通配符比字符串匹配会复杂点,所以性能也会稍弱,推荐是使用字符串匹配方式
数据加密
-
为啥要加解密
- 明文数据容易泄露,比如密码明文存储,万一泄露则会造成严重后果
-
什么是散列算法
- 一般叫hash,简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数,适合存储密码,比如MD5
-
什么是salt(盐) 667788——》aabbcc
- 如果直接通过散列函数得到加密数据,容易被对应解密网站暴力破解,一般会在应用程序里面加特殊的自动进行处理,比如用户id,例子:加密数据 = MD5(明文密码+用户id), 破解难度会更大,也可以使用多重散列,比如多次md5
-
Shiro里面 CredentialsMatcher,用来验证密码是否正确,
源码:AuthenticatingRealm -> assertCredentialsMatch()
一般会自定义验证规则 @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //散列算法,使用MD5算法; hashedCredentialsMatcher.setHashAlgorithmName("md5"); //散列的次数,比如散列两次,相当于 md5(md5("xxx")); hashedCredentialsMatcher.setHashIterations(2); return hashedCredentialsMatcher; }
权限角色控制 @RequiresRoles, @RequiresPermissions等注解的使用和编程式控制
1、配置文件的方式
使用ShiroConfig
2、注解方式
- @RequiresRoles(value={"admin", "editor"}, logical= Logical.AND)
- 需要角色 admin 和 editor两个角色 AND表示两个同时成立
-
@RequiresPermissions (value={"user:add", "user:del"}, logical= Logical.OR)
- 需要权限 user:add 或 user:del权限其中一个,OR是或的意思。
-
@RequiresAuthentication
- 已经授过权,调用Subject.isAuthenticated()返回true
-
@RequiresUser
- 身份验证或者通过记 住我登录的
3、编程方式
Subject subject = SecurityUtils.getSubject();
//基于角色判断
if(subject.hasRole(“admin”)) {
//有角色,有权限
} else {
//无角色,无权限
}
//或者权限判断
if(subject.isPermitted("/user/add")){
//有权限
}else{
//无权限
}
- 常见API
- subject.hasRole("xxx");
- subject.isPermitted("xxx");
- subject. isPermittedAll("xxxxx","yyyy");
- subject.checkRole("xxx"); // 无返回值,可以认为内部使用断言的方式
Shiro 缓存模块
-
什么是shiro缓存
- shiro中提供了对认证信息和授权信息的缓存。
- 默认是关闭认证信息缓存的,对于授权信息的缓存shiro默认开启的(因为授权的数据量大 变动小)角色的权限变化很小
- 缓存的实效性,如修改了密码不能马上在缓存中拿到,登陆不了(当然可以通过广播)
- shiro中提供了对认证信息和授权信息的缓存。
-
AuthenticatingRealm 及 AuthorizingRealm 分别提供了对AuthenticationInfo 和 AuthorizationInfo 信息的缓存。
Shiro Session模块
-
什么是会话session
- 用户和程序直接的链接,程序可以根据session识别到哪个用户,和javaweb中的session类似
-
什么是会话管理器SessionManager
-
会话管理器管理所有subject的所有操作,是shiro的核心组件
-
核心方法:
-
//开启一个session Session start(SessionContext context); //指定Key获取session Session getSession(SessionKey key)
- shiro中的会话管理器有多个实现
-
-
SessionDao 会话存储/持久化
-
SessionDAO AbstractSessionDAO CachingSessionDAO EnterpriseCacheSessionDAO MemorySessionDAO
-
核心方法
//创建 Serializable create(Session session); //获取 Session readSession(Serializable sessionId) throws UnknownSessionException; //更新 void update(Session session) //删除,会话过期时会调用 void delete(Session session); //获取活跃的session Collection<Session> getActiveSessions();
- 会话存储有多个实现
附属资料:
RememberMe 1、 Cookie 写到客户端并 保存 2、 通过调用subject.login()前,设置 token.setRememberMe(true); 3、 关闭浏览器再重新打开;会发现浏览器还是记住你的 4、 注意点: - subject.isAuthenticated() 表示用户进行了身份验证登录的,即Subject.login 进行了登录 - subject.isRemembered() 表示用户是通过RememberMe登录的 - subject.isAuthenticated()==true,则 subject.isRemembered()==false, 两个互斥 - 总结:特殊页面或者API调用才需要authc进行验证拦截,该拦截器会判断用户是否是通过 subject.login()登录,安全性更高,其他非核心接口或者页面则通过user拦截器处理即可
-