Shiro<br />1、Shiro简介<br /> <br /> <br /> <br />2、Shiro架构(Shiro外部来看)<br /><br /> <br /> <br />3、Shiro架构(Shiro内部来看)<br /> <br /> <br />4、集成Spring<br /> 第一步:导入jar包<br /> 第二步:配置Shiro(参照shiro文件的spring中的webapp)<br /> (1)在web.xml中配置Shiro的Filter<br /> <br /> (2)配置applicationContext.xml(复制即可)<br /> 1、配置SecurityManager,内含cacheManager和realm<br /> <br /> 2、配置CacheManager,内含cacheManagerConfigFile<br /> <br /> 3、配置Realm,自定义Realm实现Realm接口<br /> <br /> 4、配置LifecycleBeanPostProcessor<br /> 作用:可以自动的调用Spring容器中shiro的生命周期方法<br /> <bean id="lifecycleBeanPostProcessor"<br />class="org.apache.shiro.spring.LifecycleBeanPostProcessor/> 5、配置DefaultAdvisorAutoProxyCreator<br /> 作用:启用IOC容器中使用shiro的注解,但必须配置Lifecycle<br />BeanPostProcessor之后才可以使用<br /> <br /> 6、配置shiroFilter。<br />id必须和web.xml中配置的filter-name一致,否则会抛出<br />NoSuchBeanDefinitionException异常。<br />也可以通过targetBeanName初始化参数来定义filter-name,此<br />时id和targetBeanName的值一致也可以。<br /> 属性:securityManager<br /> loginUrl<br /> successUrl<br /> unauthorizedUrl<br /> filterChainDefinitions<br /> 作用:配置哪些页面需要保护以及访问这些页面需要的权限<br /> (1)anno:可以被匿名访问<br /> (2)authc:必须认证(登录)后才可以访问的页面<br /> <br /> <br />5、URL配置细节(即Url链)<br /> 格式:url=拦截器[参数],拦截器[参数]<br /> 拦截器:<br /> anno:匿名访问,不需要登录即可访问<br />authc:需要身份认证通过后才可能访问<br />logout:登出,重定向的路径为”/”<br />roles[角色名]:角色过滤器。拥有相应的角色才能访问相应的页面<br /> 配置模式:<br /> <br /> 匹配顺序:第一次优先匹配的方式,优先级逐渐降低<br /> <br />6、认证思路分析<br /> 第一步:调用SecurityUtils.getSubject()获取当前的Subject<br /> 第二步:调用Subject的isAuthenticated()测试当前的用户是否已经被<br />认证,即是否登录<br /> 第三步:若没有被认证,则把用户名和密码封装为UsernamePasswordToken<br />对象<br /> (1)创建一个表单页面<br /> (2)把请求提交到SpringMVC的Handler<br /> (3)获取用户名和密码<br /> 第四步:调用Subject的login(AuthenticationToken)方法,执行登录<br /> 第五步:自定义Realm的方法,从数据库中获取对应的记录,返回给Shiro (1)实际上需要继承AuthenticatingRealm类,实现<br />doGetAuthenticationInfo(AuthenticationToken)方法<br />第六步:由shiro完成密码的比对<br /> <br />7、实现认证流程<br /> 第一步:编写登陆的表单页面<br /> 第二步:编写Handler,处理请求<br /> 第三步:自定义Realm(没实现)<br /> 实际上:login方法将参数Token对象传给了Realm类中的<br /> doGetAuthenticationInfo方法的参数<br /> <br />8、实现认证Realm<br /> 第一步:自定义Realm,继承AuthenticatingRealm类<br /> 第二步:实现doGetAuthenticationInfo方法<br /> 1、把AuthenticationToken转换为UsernamePasswordToken<br /> 2、从UsernamePasswordToken中获取Username<br /> 3、调用数据库中的方法,从数据库中查询username对应的用户记录<br /> 4、若用户不存在,则可以抛出UnknownAccountException异常<br /> 5、根据用户的信息,决定是否需要抛出其它的<br />AuthenticationException异常<br /> 6、 根据用户的情况,来构建AuthenticationInfo对象并返回,通常使<br />用的实现类为:SimpleAuthenticationInfo<br />SimpleAuthenticationInfo(principal,credentials,realmName)<br />参数1:认证消息。可以是username,也可以是数据表对应的<br />用户的实体类对象<br />参数2:从数据表中获取的密码<br />参数3:当前Realm对象的name,调用父类的getName()方法即可<br /> <br />9、密码的比对<br /> 通过AuthenticatingRealm的credentialsMatcher属性来进行密码的比对<br />10、密码的MD5加密<br />替换当前的credentialsMatcher属性,直接使用HashedCredentialsMatcher<br />对象,并设置加密算法,shiro就能将前台传来的密码进行自动加密。<br /><br />手动加密:<br /> Object result=new SimpleHash(“MD5”,密码,盐值,加密次数);<br />11、密码的MD5盐值加密<br /> 盐值:ByteSource salt=ByteSource.Util.bytes(“唯一的字符串”);<br /> SimpleAuthenticationInfo(principal,credentials,salt,realmName)<br />参数1:认证消息。可以是username,也可以是数据表对应的<br />用户的实体类对象<br />参数2:从数据表中获取的密码<br />参数3:盐值<br />参数4:当前Realm对象的name,调用父类的getName()方法即可<br /> <br />12、多Realm验证<br /> 第一个Realm:使用MD5盐值加密<br /> 第二个Realm:使用SHA1盐值加密<br /> 将Realm注册IOC容器中:<br /> <br /> 原理:Shiro会进入ModularRealmAuthenticator类,进行判断是否存<br />在多个Realm。<br /><br /> 配置ModularRealmAuthenticator:<br /> <br /> 将ModularRealmAuthenticator注入到SecurityManager:<br /><br /> <br />13、Shiro的认证策略<br /> <br /> 认证策略类:AuthenticationStrategy<br /> ModularRealmAuthenticator默认的认证策略是:<br /> <br /> 修改认证策略,在ModularRealmAuthenticator的配置中修改:<br /> <br /> <br />14、把realms配置给SecurityManager<br /> 原理:实际上将配置给SecurityManager的Realms,又设置给了<br />Authenticator的setRealms。<br /><br /> <br /> <br />15、权限配置<br /> 授权方式(3种):<br /> 编程式:通过写if/else授权代码块来完成<br /> 注解式:通过在执行的java方法上放置相应的注解完成,没有权限<br />将抛出相应的异常<br /> JSP/GSP标签:在JSP/GSP页面通过相应的标签完成<br /><br />拦截器的所有种类:<br /> <br />(1)身份验证相关<br /> <br />(2)授权相关 <br /> <br />16、授权流程分析<br />(1)授权需要继承AuthorizingRealm类,并实现其<br />doGetAuthorizationInfo方法<br />(2)AuthorizingRealm类继承AuthenticatingRealm,但没有实现<br />AuthenticatingRealm中的doGetAuthenticationInfo方法,所以认证<br />和授权只需要继承AuthorizingRealm类,并实现它的两个抽象方法<br /> <br />17、实现授权Realm<br />(1)继承AuthorizingRealm类,并实现其两个方法<br /> 1、doGetAuthenticationInfo :用于认证<br /> 2、doGetAuthorizationInfo(PrincipalCollection) :用于授权<br />(2)从PrincipalCollection中获取登录用户的信息<br /> Realm配置顺序的不同,获取到的用户信息也不同。优先配置的<br />Realm,就优先获取到该Realm设置的用户信息。<br />(3)利用登录的用户信息来获取当前用户的角色(可能需要查询数据库)<br />(4)创建SimpleAuthorizationInfo对象,并设置roles属性<br /> new SimpleAuthorizationInfo(Set<String> roles)<br /> SimpleAuthorizationInfo.addRole(String roles)<br /> SimpleAuthorizationInfo.setRoles(Set<String> roles)<br />(5)返回SimpleAuthorizationInfo对象<br /> <br />18.Shiro标签<br />概述:Shiro提供了JSTL标签用于在JSP页面进行权限控制,如根据登录用<br />户显示相应的页面按钮。<br /> <br /> guest标签:用户没有身份验证时显示相应信息,即游客访问信息:<br /> <shiro:guest><br /> 欢迎游客访问,<a href=”login.jsp”></a><br /> </shiro:guest><br /> <br /> user标签:用户已经经过认证/记住我登录后显示相应的信息。<br /> </shiro:user><br /> 欢迎[<shiro:principal/>]登录,<a href=”logout”>退出</a><br /> </shiro:user><br /> <br /> authenticated标签:用户已经身份验证通过,即Subject.login登录成功,<br />不是记住我登录的<br /> <shiro:authenticated><br /> 用户[<shiro:principal/>]已经身份验证通过<br /></shiro:authenticated><br /> <br /> notAuthenticated标签:用户未进行身份验证,即没有调用Subject.login<br />进行登录,包括记住我自动登录的也属于未进行<br />身份验证<br /> <shiro:notAuthenticated><br /> 未身份验证(包括记住我)<br /></shiro:notAuthenticated><br /> <br /> principal标签:显示用户身份信息,默认调用Subject.getPrincipal()获<br />取,即Primary Principal<br /> <shiro:principal property=”username”/><br /> <br /> hasRole标签:如果当前Subject有角色将显示body体内容<br /> <shiro:hasRole name=”admin”><br /> 用户[<shiro:principal/>]拥有角色admin<br/><br /></shiro:hasRole><br /> <br /> hasAnyRoles标签:如果当前Subject有任意一个角色将显示在body体内容 <shiro:hasAnyRoles name=”admin,user”><br /> 用户[<shiro:principal/>]拥有角色admin或user<br/><br /></shiro:hasAnyRoles><br /> <br /> <br />lackRole标签:如果当前Subject没有角色将显示body体内容<br /> <shiro:lackRole name=”admin”><br /> 用户[<shiro:principal/>]没有角色admin<br/><br /></shiro:lackRole><br /> <br /> hasPermission标签:如果当前Subject有权限将显示body体内容<br /> <shiro:hasPermission name=”user:create”><br /> 用户[<shiro:principal/>]拥有权限user:create<br /></shiro:hasPermission><br /> <br /> lacksPermission标签:如果当前Subject没有权限将显示body体内容<br /> <shiro:lacksPermission name=”org:create”><br /> 用户[<shiro:principal/>]没有权限org.create<br/><br /></shiro:lacksPermission><br /> <br /> 使用:在jsp页面中导入<%@ taglib prefix=”shiro”<br />uri=”[http://shiro.apache.org/tags](http://shiro.apache.org/tags)”%><br /> <br />19、权限注解<br /><br /> 注意:当Service使用事务注解时,该shiro相关的注解就不能使用在<br />Service层,而是使用在Controller层<br /> <br />20、从数据库中初始化资源和权限<br />配置url权限的方式:setFilterChainDefinitionMap(Map<String,String>)<br />在shiroFilter中配置filterChainDefinitionMap:<br /> <br /><br /><br /> <br />21、会话管理<br /> <br /> <br />作用:在Service层无法获取HttpSession,因此在Service层使用Shiro<br />提供的Session,从而获取Session域中的数据。<br /> <br />22、SessionDao <br /> <br /><br />第一步:自定义类,继承EnterpriseCacheSessionDAO<br />第二步:配置三个bean,SessionManager配置给securityManager<br />第三步:实现方法,对Session要进行序列化和反序列化<br /> <br />23、缓存<br /><br /><br /> <br />24、记住我<br /><br /><br /><br /> <br />25、实现RememberMe<br />原理:实际上是SecurityManager的RememberManager中的cookie来保存密码<br />设置时间:通过设置cookie的属性maxAge(单位:秒)<br /><br /> 实现:token.setRememberMe(true);<br /> <br />