applicationContext 中配置
<!-- Shiro配置 -->
<!-- 用户授权信息Cache:缓存控制器,来管理如用户、角色、权限等的缓存的;
因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能 -->
<bean id="memoryConstrainedCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
<!-- 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证的类 -->
<bean id="myRealm" class="com.lanou.shiro.MyShiroRealm">
<!-- 把realm对象添加到shiro的缓存中 -->
<property name="cacheManager" ref="memoryConstrainedCacheManager" />
</bean>
<!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替
securityManager相当于SpringMVC中的DispatcherServlet,所有的校验工作都先进入它,
由它指派具体的校验realm
-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 把自定义的realm注入到SecurityManager中:
把realm对象交由SercurityManager进行管理
-->
<property name="realm" ref="myRealm"/>
<!-- 配置多个realm -->
<!-- <property name="realms">
<list>
<ref bean="realm1"/>
<ref bean="realm2"/>
</list>
</property> -->
</bean>
<!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的自定义过滤器的执行 -->
<!-- Web应用中,Shiro可控制Web请求必须经过Shiro主过滤器进行拦截,Shiro对基于Spring的Web应用提供了完美的支持 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager"/>
<!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找webapp根目录下的"/login.jsp"页面 -->
<property name="loginUrl" value="/admin/login.jsp"/>
<!-- 登录成功后要跳转的连接(我们这里该属性用不到,因为登录成功后的处理逻辑在login.js中硬编码为index.jsp了) -->
<!-- <property name="successUrl" value="/admin/index.jsp"/> -->
<!-- 用户访问未对其授权的资源时,所显示的视图 -->
<property name="unauthorizedUrl" value="/admin/no-perm.jsp"/>
<!-- Shiro约束配置,即过滤链的定义 -->
<!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath() -->
<!-- anon:放行,不进行校验 -->
<!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->
<property name="filterChainDefinitions">
<value>
<!-- 登录页面和错误不需要验证 -->
/admin/login.jsp = anon
/admin/no-perm.jsp = anon
<!-- 需要验证 -->
导shiro相关jar包或者在maven 中注入依赖
<!-- Shiro 安全校验框架 --> <!-- Spring 整合Shiro需要的依赖 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.1</version> </dependency>
/admin/index.jsp = authc /admin/system-menu-list.jsp = authc,perms["system-menu-list"] /admin/system-role-list.jsp = authc,perms["system-role-list"] 等等等等 <!-- 需要验证具有role_001角色的用户可以访问,多用于跳转页面 可以配置多个,要用英文双引号扩起来用英文逗号分隔,例如roles["role_001,role_002"] --> <!-- /user/toImportUsers.do = authc,roles[role_001] /ztree/toZtree.do = authc,roles["role_001,role_002"] 需要验证具有role_001角色的selUserInfo权限的用户可以访问 ,多用于页面中某个请求 /user/selUserInfo.do = authc,perms[role_001:selUserInfo] 需要验证具有role_001角色的selUserInfo权限的用户可以访问 ,多用于页面中某个请求 /user/importUsers.do = authc,perms["role_001:add:,role_002:modify"] --> <!-- 不在被校验的url全部放行 --> /** = anon </value> </property> </bean> <!-- 管理shiroBean的生命周期 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- 权限shiro配置 结束 --> 在 web.xml 中 添加 shiro 过滤器配置<!-- 需要放行的地址 -->
<!-- shiro过滤器配置一定要写到DispatcherServlet之前 --> <filter> <!-- 注意DelegatingFilterProxy是一个代理类: web.xml中的filter-name必须和applicationContext.xml中配置的filter的id一致 --> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <!-- 交由Spring管理Shiro对象的创建和销毁 --> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
---------------------神秘的分割线-------------------------------------------------------
controller 中加一个shiro 类
package com.lanou.shiro; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import com.lanou.domain.Menu; import com.lanou.domain.User; import com.lanou.service.MenuService; import com.lanou.service.UserService; /** * 自定义Shiro校验规则:继承AuthorizingRealm * * */ public class MyShiroRealm extends AuthorizingRealm { @Autowired private MenuService menuService; @Autowired private UserService userService; /** * 权限校验:Authorization授权 为当前登录的Subject授予角色和权限 该方法在为需授权资源被访问时调用 * Principal是Subject的标识,一般情况下是唯一标识,比如用户名。 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.err.println("----验证当前登录用户拥有的权限或角色----"); // 获取当前登录的用户名 String currentUsername = (String)super.getAvailablePrincipal(principals); // 角色列表 List<String> roleList = new ArrayList<String>(); // 权限列表 List<String> permissionList = new ArrayList<String>(); // 从数据库中获取当前登录用户拥有的所有菜单 List<Menu> menus = menuService.getByUsername(currentUsername); if(menus != null && menus.size() > 0){ for(Menu menu : menus){ permissionList.add(menu.getUrlkey()); } } // 为当前用户设置角色和权限 // 把校验信息封装到SimpleAuthorizationInfo对象中 SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo(); simpleAuthorInfo.addRoles(roleList); simpleAuthorInfo.addStringPermissions(permissionList); return simpleAuthorInfo; } /** * 登录校验:Authentication身份认证 验证当前登录的Subject * 该方法在LoginController的login()方法执行Subject.login()时被调用 进行身份认证的目的:
校验了3次 登录 一次 权限检验中一次 * 1.一定程度上防止非法登录 2.把通过身份认证的用户信息封装到AuthenticationInfo对象中, * 从而把已认证的用户交由SecurityManager进行管理 在logout之前不再对该用户的后续请求进行身份校验 * */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { // 获取基于用户名和密码的令牌 // 参数中的authcToken是从LoginController里面currentUser.login(token)传过来的 UsernamePasswordToken token = (UsernamePasswordToken)authcToken; System.err.println( "验证当前Subject获取到的token为:" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE)); // 通过token.getUsername():获取登录的用户名 User user = userService.getUserByName(token.getUsername()); System.err.println("principal:" + token.getPrincipal()); if(user != null){ //this.getName():org.apache.shiro.realm.CachingRealm.getName() // 把通过身份校验的用户信息封装到AuthenticationInfo对象中 封装到缓存中 浏览器退出之前 ,可以不用重新登录 // 在logout之前不再对该用户的后续请求进行身份校验 AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), this.getName()); return authcInfo; } return null; } }
在登录的 时候 进行 shiro 判断shiro 判断 1.先检验 用户身份
2.shiro 中再次 调用 user.getUsername 和user.password 再次检验 避免 非法登录