一、认识
Spring中的security:重量级的安全框架、是细粒度的、功能很多
Apache中的Shiro:轻量级安全框架、是粗粒度,功能没有security多,但是也足够用了
二、shiro的四大基石
身份验证、授权、密码学、会话管理
三、shiro的架构
Submit:当前用户
Shiro securityManager:权限管理器、shiro的核心类、所有功能的核心
Realm:读取当前用户的信息、登录权限和角色
四、shiro与spring的集成
1.导包
1 <!-- shiro的支持包 --> 2 <dependency> 3 <groupId>org.apache.shiro</groupId> 4 <artifactId>shiro-all</artifactId> 5 <version>1.4.0</version> 6 <type>pom</type> 7 </dependency> 8 <!-- shiro与Spring的集成包 --> 9 <dependency> 10 <groupId>org.apache.shiro</groupId> 11 <artifactId>shiro-spring</artifactId> 12 <version>1.4.0</version> 13 </dependency>
2.配置web.xml
<!-- Shiro的过滤器(拦截所有请求) --> <!-- 这个过滤器只过滤,它什么功能都没有! 它什么都不做! 真正的过滤功能是在Spring中的过滤器完成的!!! 名字很重要:必需和shiro.xml中的过滤器名称一样 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <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>
3.准备自定义realm
1 public class CRMRealm extends AuthorizingRealm { 2 3 @Autowired 4 private IEmployeeService employeeService; 5 @Autowired 6 private IPermissionService permissionService; 7 8 @Override 9 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 10 //获取主体 11 Employee employee = (Employee) principalCollection.getPrimaryPrincipal(); 12 //获取权限 13 Set<String> perms = permissionService.findByUserId(employee.getId()); 14 15 //创建对象 16 SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); 17 simpleAuthorizationInfo.setStringPermissions(perms); 18 return simpleAuthorizationInfo; 19 } 20 21 @Override 22 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { 23 //获取令牌 24 UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; 25 //获取用户名 26 String username = token.getUsername(); 27 //通过用户名在数据库获取密码 28 Employee employee = employeeService.findByLoginUsername(username); 29 if(employee==null){ 30 return null; 31 } 32 //创建对象 33 //盐值 34 ByteSource salt = ByteSource.Util.bytes("su"); 35 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(employee, employee.getPassword(), salt,getName()); 36 return simpleAuthenticationInfo; 37 }
4.自定义拦截器
1 public class FilterChainDefinitionMapBuilder { 2 @Autowired 3 private IPermissionService permissionService; 4 5 public Map<String,String> createFilterChainDefinitionMap(){ 6 LinkedHashMap<String, String> filterChainDefinitionBuilderMap = new LinkedHashMap<>(); 7 //放行 8 filterChainDefinitionBuilderMap.put("/static/**", "anon"); 9 filterChainDefinitionBuilderMap.put("/login.jsp", "anon"); 10 filterChainDefinitionBuilderMap.put("/login/login", "anon"); 11 filterChainDefinitionBuilderMap.put("/department/list", "anon"); 12 13 //拦截 14 List<Permission> perms = permissionService.findAll(); 15 perms.forEach(e->{ 16 // perms 改成自定义拦截器的key aiSell 17 filterChainDefinitionBuilderMap.put(e.getUrl(), "aiSell["+e.getSn()+"]"); 18 }); 19 20 filterChainDefinitionBuilderMap.put("/**", "authc"); 21 return filterChainDefinitionBuilderMap; 22 } 23 }
5.重写ajax请求的返回值
1 public class CRMPermissionsAuthorizationFilter extends PermissionsAuthorizationFilter { 2 3 @Override 4 protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { 5 Subject subject = this.getSubject(request, response); 6 if (subject.getPrincipal() == null) { 7 this.saveRequestAndRedirectToLogin(request, response); 8 } else { 9 //到这表示你没有权限 10 //强转成我们需要的http 11 HttpServletRequest httpRequest = (HttpServletRequest) request; 12 HttpServletResponse httpResponse = (HttpServletResponse) response; 13 //2.请求头有X-Requested-With表示为ajax请求 14 String xRequestedWith = httpRequest.getHeader("X-Requested-With"); 15 if ("XMLHttpRequest".equals(xRequestedWith)) { 16 //3.在这里就代表是ajax请求 17 //表示ajax请求 {"success":false,"message":"没有权限"} 18 httpResponse.setContentType("application/json; charset=UTF-8"); 19 //注意print没有ln 20 httpResponse.getWriter().print("{\"success\":false,\"msg\":\"还没有权限哦~\"}"); 21 }else { 22 String unauthorizedUrl = this.getUnauthorizedUrl(); 23 if (StringUtils.hasText(unauthorizedUrl)) { 24 WebUtils.issueRedirect(request, response, unauthorizedUrl); 25 } else { 26 WebUtils.toHttp(response).sendError(401); 27 } 28 } 29 } 30 return false; 31 } 32 }
6.配置applicationContex-shiro.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation=" 5 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> 6 7 8 <!--shiro的核心类--> 9 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 10 <property name="realm" ref="aiSellRealm"/> 11 </bean> 12 13 <!--自定义realm--> 14 <bean id="aiSellRealm" class="cn.susu.web.shiro.CRMRealm"> 15 <property name="credentialsMatcher"> 16 <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> 17 <property name="hashAlgorithmName" value="MD5"/> 18 <property name="hashIterations" value="10"/> 19 </bean> 20 </property> 21 </bean> 22 23 <!--支持注解权限判断--> 24 <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> 25 <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" 26 depends-on="lifecycleBeanPostProcessor"/> 27 <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> 28 <property name="securityManager" ref="securityManager"/> 29 </bean> 30 31 <!--shiro真正的过滤器 名字与web.xml中的一致--> 32 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 33 <property name="securityManager" ref="securityManager"/> 34 <!--登录失败返回的页面--> 35 <property name="loginUrl" value="/index.jsp"/> 36 <!--登录成功返回的页面--> 37 <property name="successUrl" value="/department/index"/> 38 <!--登录成功后没有权限跳转的界面--> 39 <property name="unauthorizedUrl" value="/shiro/unauthorized.jsp"/> 40 <!--<property name="filterChainDefinitions"> 41 <value> 42 /s/login = anon 43 /login=anon 44 /employee/index = perms[employee:index] 45 /** = authc 46 </value> 47 </property>--> 48 <property name="filterChainDefinitionMap" ref="filterChainDefinitionBuilderMap"></property> 49 <property name="filters"> 50 <map> 51 <!--/employee/index = aiSell[employee:index]--> 52 <entry key="aiSell" value-ref="aiSellFilter"></entry> 53 </map> 54 </property> 55 </bean> 56 <!--自定义拦截器--> 57 <bean id="aiSellFilter" class="cn.susu.web.shiro.CRMPermissionsAuthorizationFilter"></bean> 58 <!--数据库查拦截权限--> 59 <bean id="filterChainDefinitionBuilderMap" factory-bean="filterChainDefinitionMapBuilder" factory-method="createFilterChainDefinitionMap"></bean> 60 <bean id="filterChainDefinitionMapBuilder" class="cn.susu.web.shiro.FilterChainDefinitionMapBuilder"></bean> 61 </beans>