河北精品网站建设,flash html网站模板,重庆城乡建设部网站首页,我想阻止一个网站要怎么做Shiro
1.权限管理概述 2.Shiro权限框架 2.1 概念 2.2 Apache Shiro 与Spring Security区别 3.Shiro认证 3.1 基于ini认证 3.2 自定义Realm --认证 4.Shiro授权 4.1 基于ini授权 4.2 自定义realm – 授权 5.项目集成shiro 认证-授权注意点 5.1 认证…Shiro
1.权限管理概述 2.Shiro权限框架 2.1 概念 2.2 Apache Shiro 与Spring Security区别 3.Shiro认证 3.1 基于ini认证 3.2 自定义Realm --认证 4.Shiro授权 4.1 基于ini授权 4.2 自定义realm – 授权 5.项目集成shiro 认证-授权注意点 5.1 认证 5.2 授权 5.3 注解RequiresPermissions() 5.4 标签式权限验证 6.Shiro加密 7.Shiro缓存
权限管理概述
RBAC(Role Based Access Control) :某个用户拥有什么角色,被允许做什么事情(权限) 用户登录—分配角色----(权限关联映射)----鉴权(拥有什么什么权限)
熟悉框架流程
概念 能做什么架构是怎样代码怎么实现项目运用
Shiro权限框架
概念: Apache Shiro 是一个强大且易用的 Java 安全框架
能做什么:Shiro可以帮我们完成 :认证、授权、加密、会话管理、与 Web 集成、缓存等。架构是怎样的 主要认识:Subject(用户)当前的操作用户 获取当前用户Subject currentUser SecurityUtils.getSubject()SecurityManager安全管理器Shiro的核心,负责与其他组件进行交互,实现 subject 委托的各种功能Realms数据源 Realm会查找相关数据源,充当与安全管理间的桥梁,经过Realm找到数据源进行认证,授权等操作Authenticator认证器):用于认证从 Realm 数据源取得数据之后进行执行认证流程处理。Authorizer授权器)用户访问控制授权决定用户是否拥有执行指定操作的权限。SessionManager 会话管理器:支持会话管理CacheManager 缓存管理器)用于缓存认证授权信息Cryptography加密组件提供了加密解密的工具包
Apache Shiro 与Spring Security区别
Shiro::用于中小型项目比较常见,简单易上手,可以支持多种环境 Shiro 可以不跟任何的框架或者容器绑定可独立运行 Spring Security:一般多用于spring环境,中大型项目,更强大 Spring Security 则必须要有Spring环境
Shiro认证
基于ini认证
1.新建项目 --导入依赖--新建 配置文件ini2. shiro帮我们创建用户创建令牌 ,类比页面传入的账号密码密码错误-- IncorrectCredentialsException账号错误-- UnknownAccountException导入依赖
dependencygroupIdcommons-logging/groupIdartifactIdcommons-logging/artifactIdversion1.1.3/version
/dependency
dependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-core/artifactIdversion1.5.2/version
/dependencydependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.13.2/version
/dependency
dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.16.22/versionscopeprovided/scope
/dependency编写ini,shiro默认支持的是ini配置的方式(只是演示) shiro-au.ini,真实项目使用xml
#用户的身份、凭据
[users]
zhangsan555
xiaoluo666使用 Shiro 相关的 API 完成身份认证
Test
public void testLogin(){//创建Shiro的安全管理器是shiro的核心DefaultSecurityManager securityManager new DefaultSecurityManager();//加载shiro.ini配置得到配置中的用户信息账号密码IniRealm iniRealm new IniRealm(classpath:shiro-au.ini);securityManager.setRealm(iniRealm);//把安全管理器注入到当前的环境中SecurityUtils.setSecurityManager(securityManager);//无论有无登录都可以获取到subject主体对象但是判断登录状态需要利用里面的属性来判断Subject subject SecurityUtils.getSubject();System.out.println(认证状态subject.isAuthenticated());//创建令牌(携带登录用户的账号和密码)UsernamePasswordToken token new UsernamePasswordToken(xiaoluo,666);//执行登录操作(将用户的和 ini 配置中的账号密码做匹配)subject.login(token);System.out.println(认证状态subject.isAuthenticated());//登出//subject.logout();//System.out.println(认证状态subject.isAuthenticated());
}自定义Realm–认证
模拟
Getter
Setter
public class Employee {private String username;private String password;}思路: //继承 AuthorizingRealm //参数的token ,subject进行登录匹配传入的token : UsernamePasswordToken 1.获取用户名 方式一:将token强转为UsernamePasswordToken–getUsername() 方式二:通过token.getPrincipal() 2.以用户名为条件,查询mysql数据库,得到用户对象(用户名/密码) 模拟从数据库查询的对象 -------自己new一个 3.将用户对象封装成认证info对象返回 //存在两种可能 1.用户对象为null----- return null 2.不为空 ----封装数据 return new SimpleAuthenticationInfo( 有3个参数 1.employee , //从数据库查询出来需要进行密码匹配的用户对象 2.employee.getPassword(), //匹配对象密码 3.super.getName() //指定realm的名称 ,可自定义 ) 实现:
public class Realm extends AuthorizingRealm {//认证Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//1.获取登录用户名String username (String) token.getPrincipal();//2.以用户名为条件查询mysql数据库,得到用户对象//模拟数据Employee employee new Employee();employee.setUsername(xiaoluo);employee.setPassword(123);//封装成一个认证info对象//判断用户是否为空if (employee!null){return new SimpleAuthenticationInfo(employee,employee.getPassword(),super.getName());}return null;}
}Test
public void testLogin(){//创建Shiro的安全管理器是shiro的核心DefaultSecurityManager securityManager new DefaultSecurityManager();//自定义Realm,查出用户信息Realm realm new Realm();securityManager.setRealm(realm);//把安全管理器注入到当前的环境中SecurityUtils.setSecurityManager(securityManager);//无论有无登录都可以获取到subject主体对象但是判断登录状态需要利用里面的属性来判断Subject subject SecurityUtils.getSubject();System.out.println(认证状态subject.isAuthenticated());//创建令牌(携带登录用户的账号和密码)UsernamePasswordToken token new UsernamePasswordToken(xiaoluo,123);//执行登录操作(将用户的和 ini 配置中的账号密码做匹配)subject.login(token);System.out.println(认证状态subject.isAuthenticated());//登出//subject.logout();//System.out.println(认证状态subject.isAuthenticated());
}Shiro授权
基于ini授权
登录分配鉴权 权限表达式 资源:操作 admin: //超级管理员 empemployee:* //判断是否有某个角色
subject.hasRole(role);
//用户拥有所有指定角色返回true
subject.hasAllRoles(Arrays.aList(role1,role2));
//判断用户是否有指定角色,将结果返回,封装到boolean数组中
boolean[] booleanssubject.hasRoles(Arrays.aList(role1,role2));
//check开头的是没有返回值,当没有权限时就会抛出异常
subject.checkRole(role);
//判断用户是否有某个权限
subject.isPermitted(权限表达式)
boolean[] booleanssubject.isPermitted(权限表达式1,权限表达式2)自定义realm — 授权
思路: 1.获取当前登录用户的id/name //获取当前登录用户对象 ,登录传过来的第一个参数 方式一 :principals.getPrimaryPrincipal(); 方式二:SecurityUtils.getSubject().getPrincipal(); 2.以用户id作为条件查询mysql数据,查询该用户拥有角色/权限 //假装查数据 //List roles roleService.queryByEmployee(Employee.getId()); //List //List roles permissionService.queryByEmployee(Employee.getId()); permissionService.queryByEmployee(Employee.getId()); 3.将角色与权限封装到授权info对象中 SimpleAuthorizationInfo info new SimpleAuthorizationInfo(); info.addRoles(roles) //添加角色 info.addStringPermission(permission);//添加权限 实现:
//授权Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {//获取当前用户对象Employee employee (Employee)principalCollection.getPrimaryPrincipal();//以用户id查询数据库,判断该角色/用户是否拥有权限 模拟ListString roles Arrays.asList(seller);ListString permissions Arrays.asList(customer:list,customer:save);//封装到info对象SimpleAuthorizationInfo info new SimpleAuthorizationInfo();info.addRoles(roles);info.addStringPermissions(permissions);return info;}public class ShiroDemo {Testpublic void testLogin(){//创建Shiro的安全管理器是shiro的核心DefaultSecurityManager securityManager new DefaultSecurityManager();//加载shiro.ini配置得到配置中的用户信息账号密码IniRealm iniRealm new IniRealm(classpath:shiro-author.ini);//自定义Realm,查出用户信息Realm realm new Realm();securityManager.setRealm(realm);//把安全管理器注入到当前的环境中SecurityUtils.setSecurityManager(securityManager);//无论有无登录都可以获取到subject主体对象但是判断登录状态需要利用里面的属性来判断Subject subject SecurityUtils.getSubject();System.out.println(认证状态subject.isAuthenticated());//创建令牌(携带登录用户的账号和密码)UsernamePasswordToken token new UsernamePasswordToken(xiaoluo,12);//执行登录操作(将用户的和 ini 配置中的账号密码做匹配)subject.login(token);System.out.println(认证状态subject.isAuthenticated());//登出//subject.logout();//System.out.println(认证状态subject.isAuthenticated());//判断用户是否有某个角色System.out.println(hr:subject.hasRole(hr));System.out.println(seller:subject.hasRole(seller));//是否同时拥有多个角色System.out.println(是否同时拥有role1和role2subject.hasAllRoles(Arrays.asList(hr, seller)));boolean[] booleans subject.hasRoles(Arrays.asList(hr, seller));//System.out.println(booleans);//check开头的是没有返回值的当没有权限时就会抛出异常subject.checkRole(seller);//判断用户是否有某个权限System.out.println(user:delete:subject.isPermitted(user:delete));subject.checkPermission(customer:list);}
}//如果用户是超级管理员 //设置超级管理员角色info.addRole(admin)//设置超级管理员权限
info.addStringPermission(*:*);项目集成shiro 认证-授权注意点
认证 1.添加对应依赖 2.配置代理过滤器 为什么不用配置拦截器? Shiro是选择使用filter过滤器来进行拦截的因为Shiro不依赖Spring容器所以当没有springmvc时意味着不能用拦截器但过滤器则不同只要是web项目都可以使用 3.创建shiro.xml 4.配置shiro过滤器 5.配置安全管理器 DefaultWebSecurityManager 6.修改LoginController 7.配置自定义Realm 8.将自定义Realm交给容器管理 shiro中的过滤器 anon: 匿名处理过滤器即不需要登录即可访问一般用于静态资源过滤/static/**anonauthc: 表示需要认证(登录)才能使用;(放最后) /**authclogout: 注销过滤器 /logoutlogoutroles: 角色授权过滤器验证用户是否拥有资源角色/employee/inputperms[“user:update”]
授权
没有权限的异常 :org.apache.shiro.authz.UnauthorizedException shiro注解鉴权操作方式: 类比RBAC: 1.自定义权限注解 2.将注解贴在请求映射方法上面 3.将注解标注的权限表达式加载到数据库中 4.将这些表达式根据用户角色进行权限分配 5.当用户登录之后,访问某个请求映射方法时,先经过权限拦截器,进行鉴权操作 1.获取当前登录用户权限表达式集合 2.获取当前请求映射方法头顶上权限表达式 3.判断用户权限表达式集合中是否包含该表达式 Shiro 权限验证三种方式
编程式注解式页面标签式
1.编程式Subject subject SecurityUtils.getSubject();
if(subject.hasRole(hr)) {//有权限
} else {//无权限
}2.注解式
RequiresRoles(admin)
RequiresPermissions(user:create)
public void hello() {//有权限
}3.页面标签式shiro.hasPermission nameemployeelist!-- 有权限 --
/shiro.hasRole授权步骤 1.贴注解 2.开启 Shiro 注解扫描器 3.查询数据库真实数据 自定义realm 注解RequiresPermissions()
value属性 这个属性是一个数组Logical.AND 必须同时拥有value配置所有权限才允许访问Logical.OR只需要拥有value配置所有权限中一个即可允许访问 约定:权限表达式,第一值权限表达式,第二值为权限名称 RequiresPermissions(value{“employee:list”,“员工列表”},logicalLogical.OR) 逻辑为OR,value满足其中一个条件成立 标签式权限验证
拓展FreeMarker标签
默认的freemarker是不支持shiro标签,所以需要做功能拓展 public class ShiroFreeMarkerConfig extends FreeMarkerConfigurer {Overridepublic void afterPropertiesSet() throws IOException, TemplateException {//继承之前的属性配置这不能省super.afterPropertiesSet();Configuration cfg this.getConfiguration();cfg.setSharedVariable(shiro, new ShiroTags());//注册shiro 标签}
} 让之前的配置文件中的FreeMarkerConfigurer修改为自定义的ShiroFreeMarkerConfig类
!-- 注册 FreeMarker 配置类 --
bean classcn.k.shiro.ShiroFreeMarkerConfig!-- 配置 FreeMarker 的文件编码 --property namedefaultEncoding valueUTF-8 /!-- 配置 FreeMarker 寻找模板的路径 --property nametemplateLoaderPath value/WEB-INF/views/ /property namefreemarkerSettingsprops!-- 兼容模式 配了后不需要另外处理空值问题时间格式除外 --prop keyclassic_compatibletrue/prop/props/property
/bean使用shiro标签
authenticated 标签已认证通过的用户。
shiro.authenticated /shiro.authenticatednotAuthenticated 标签未认证通过的用户。
shiro.notAuthenticated/shiro.notAuthenticatedprincipal 标签 输出当前用户信息通常为登录帐号信息
shiro.principal propertyname / //对应name属性hasRole 标签验证当前用户是否拥有该角色
shiro.hasRole nameadmin我是管理员/shiro.hasRolehasAnyRoles 标签验证当前用户是否拥有这些角色中的任何一个角色之间逗号分隔
shiro.hasAnyRoles nameadmin,user,hrHello admin/shiro.hasAnyRoleshasPermission 标签验证当前用户是否拥有该权限
shiro.hasPermission namedepartment:delete删除/shiro.hasPermissionShiro加密
MD5
//参数1 :原文,参数2:盐 ,参数3:散列次数(加密次数)
Md5Hash hashnew Md5Hash(1,kent,3);盐一般要求是固定长度的字符串且每个用户的盐不同。 一般盐的选择的是用户的唯一数据(账号名等),盐是要求不能改变的,不然下次加密结果就对应不上了
Shiro缓存
当我们登录时,授权信息是要从数据库中查询的,如果每次刷新刷新都需要获取你到底有没有权限,对性能影响不好,用户登录后,授权信息一般很少改动,所以,我们可以将第一次授权后,将信息存在缓存中,下次直接再缓存中获取,就很好的避免了多次访问数据库
Shiro没有实现自己的缓存机制,只提供了支持缓存的API接口,这里使用的是EhCache
集成EhCache 第三方EhCache 1.配置缓存管理器并引用缓存管理器 !--安全管理器--
bean idsecurityManager classorg.apache.shiro.web.mgt.DefaultWebSecurityManager!--注册自定义数据源--property namerealm refemployeeRealm/!--注册缓存管理器--property namecacheManager refcacheManager/
/bean!-- 缓存管理器 --
bean idcacheManager classorg.apache.shiro.cache.ehcache.EhCacheManager !-- 设置配置文件 --property namecacheManagerConfigFile valueclasspath:shiro-ehcache.xml/
/bean2.添加缓存配置文件 shiro-ehcache.xmlehcachedefaultCachemaxElementsInMemory1000eternalfalsetimeToIdleSeconds600timeToLiveSeconds600memoryStoreEvictionPolicyLRU/defaultCache
/ehcache配置缓存文件属性说明
maxElementsInMemory 缓存对象最大个数。eternal对象是否永久有效 ,一般为falsetimeToIdleSeconds 对象空闲时间timeToLiveSeconds对象存活时间memoryStoreEvictionPolicy当达到 maxElementsInMemory 限制时Ehcache 将会根据指定的策略去清理内存。LFU较少使用意思是一直以来最少被使用的缓存的元素有一个hit 属性命中率hit 值最小的将会被清出缓存默认
拓展 统一全局异常 ControllerAdvice 控制器功能增强注解 1.在进入请求映射方法之前做功能增强,经典用法:date日期格式化 2.在进入请求映射方法之后做功能增强,经典用法:统一异常处理 3.处理异常的方法,方法需要贴ExceptionHandler注解 配置文件 配置代理过滤器
filterfilter-nameshiroFilter/filter-namefilter-classorg.springframework.web.filter.DelegatingFilterProxy/filter-class
/filter
filter-mappingfilter-nameshiroFilter/filter-nameurl-pattern/*/url-pattern
/filter-mapping配置shiro.xml
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd!--引入自定义Realm--bean idemployeeRealm classcn.k.shiro.EmployeeRealm/bean!--配置安全管理器--bean idsecurityManager classorg.apache.shiro.web.mgt.DefaultWebSecurityManagerproperty namerealm refemployeeRealm/!--注册缓存管理器--property namecacheManager refcacheManager//bean!--配置shiro过滤器--bean idshiroFilterclassorg.apache.shiro.spring.web.ShiroFilterFactoryBean!--引用指定的安全管理器--property namesecurityManager refsecurityManager/!--shiro默认的登录地址是/login.jsp 现在要指定我们自己的登录页面地址--property nameloginUrl value/login.html/!--路径对应的规则--property namefilterChainDefinitionsvalue/userLoginanon/css/**anon/js/**anon/img/**anon/upload/**anon/userLogoutlogout/**authc/value/property/bean!--开启 Shiro 注解扫描器--!-- aop:config/ 会扫描配置文件中的所有advisor并为其创建代理 --aop:config/!-- Pointcut advisor通知器 会匹配所有加了shiro权限注解的方法 --bean classorg.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisorproperty namesecurityManager refsecurityManager//bean!-- 缓存管理器 --bean idcacheManager classorg.apache.shiro.cache.ehcache.EhCacheManager!-- 设置配置文件 --property namecacheManagerConfigFile valueclasspath:shiro-ehcache.xml//bean/beans关联mvc.xml
import resourceclasspath:shiro.xml/loginController
RequestMapping(/userLogin)ResponseBodypublic JsonResult login(String username, String password){try {UsernamePasswordToken token new UsernamePasswordToken(username, password);SecurityUtils.getSubject().login(token);return new JsonResult();} catch (UnknownAccountException e) {return new JsonResult(false, 账号不存在);} catch (IncorrectCredentialsException e) {return new JsonResult(false, 密码错误);} catch (Exception e) {e.printStackTrace();return new JsonResult(false, 登录异常请联系管理员);}}