1、引入依赖
<!-- 权限控制 框架 --> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.2</version>
</dependency>
2、配置web.xml
<!-- spring框架提供,整合shiro框架
一定要在Struts拦截器之前配置
DelegatingFilterProxy在创建过程中,依赖一个对象,这个对象必须在applicationContext.xml 文件中间注册,
而且注册的时候声明的ID必须和DelegatingFilterProxy声明的filter-name保持一致
-->
<filter>
<filter-name>shiroFilterFactoryBean</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilterFactoryBean</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、配置applicationContext.xml,配置全局权限
1 <!-- 初始化shiro框架提供的过滤器 --> 2 <bean id="shiroFilterFactoryBean" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 3 <!-- 注入安全管理器 --> 4 <property name="securityManager" ref="securityManager"/> 5 <!-- 权限认证的页面,登录页面 --> 6 <property name="loginUrl" value="/login.html"/> 7 <!-- 权限认证成功以后要跳转的页面 --> 8 <property name="successUrl" value="/index.html"/> 9 <!-- 权限认证失败(权限不足)以后要跳转的页面 只对拦截器生效,不对注解起效--> 10 <property name="unauthorizedUrl" value="/unauthorizedUrl.html"/> 11 <!--指定拦截规则--> 12 <property name="filterChainDefinitions" > 13 <!-- 14 authc:框架提供的过滤器,有权限就放行,没有权限就拦截 15 anon:框架提供的过滤器,可以匿名访问 16 perms:框架提供的过滤器,用户请求资源的时候,会去检查用户是否拥有对应的权限,如果有就放行,没有,跳转到unauthorizedUrl属性指定的页面 17 拦截的规则执行的时候是从上往下执行的,一旦有一个规则匹配成功.后面的规则就不再执行了 18 拦截规则不能折行 19 --> 20 <value> 21 /webService/** = anon 22 /upload/* = anon 23 /css/* = anon 24 /data/* = anon 25 /images/* = anon 26 /js/** = anon 27 /validatecode.jsp* = anon 28 /userAction_login.action = anon 29 /courierAction_pageQuery.action = perms["courierAction_pageQuery"] 30 /** = authc 31 </value> 32 </property> 33 34 </bean> 35 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 36 <!-- 配置realm类 --> 37 <property name="realm" ref="userRealm"/> 38 </bean>
4、配置applicationContext.xml开启cglib代理,启动shiro权限注解扫描
1 <!-- 2 开启事务注解 3 JDK代理 4 CGLib代理方式 5 proxy-target-class:true 使用cglib代理 6 proxy-target-class:false 使用jdk代理 7 --> 8 <tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager" /> 9 10 <!--基于spring的自动代理,创建service层的实现--> 11 <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> 12 <!--开启cglib 代理--> 13 <property name="proxyTargetClass" value="true"/> 14 </bean> 15 <!--配置切面--> 16 <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> 17 <!--注入安全管理器 --> 18 <property name="securityManager" ref="securityManager"/> 19 </bean>
5、在action层中创建subject,交由Security Manager进行权限校验
1 @Action(value = "userAction_login",results = { 2 @Result(name = "success",location = "/index.html",type = "redirect"), 3 @Result(name = "error",location = "/login.html",type = "redirect") 4 }) 5 public String login(){ 6 String serverCode = (String) ServletActionContext.getRequest().getSession().getAttribute("key"); 7 8 if (StringUtils.isNotEmpty(checkCode) && StringUtils.isNotEmpty(serverCode)){ 9 Subject subject = SecurityUtils.getSubject(); 10 11 AuthenticationToken token = new UsernamePasswordToken( 12 getModel().getUsername(),getModel().getPassword()); 13 14 try { 15 subject.login(token); 16 //方法的返回值有Realm中doGetAuthenticationInfo方法定义SimpleAuthenticationInfo对象的时候,第一个参数决定的 17 User user = (User) subject.getPrincipal(); 18 ServletActionContext.getRequest().getSession().setAttribute("user",user); 19 return SUCCESS; 20 } catch (AuthenticationException e) { 21 e.printStackTrace(); 22 System.out.println("用户名或密码错误"); 23 } 24 } 25 return ERROR; 26 }
6、创建realm进行授权认证等
1 @Component 2 public class UserRealm extends AuthorizingRealm{ 3 4 @Autowired 5 private UserRepository userRepository; 6 7 @Autowired 8 private RoleRepository roleRepository; 9 10 @Autowired 11 private PermissionRepository permissionRepository; 12 13 //授权的方法 14 @Override 15 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 16 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 17 //根据当前用户的用户名去查询对应的权限和角色 18 Subject subject = SecurityUtils.getSubject(); 19 User user = (User) subject.getPrincipal(); 20 if ("admin".equals(user.getUsername())){ 21 List<Role> list = roleRepository.findAll(); 22 for (Role role : list) { 23 info.addRole(role.getKeyword()); 24 } 25 26 List<Permission> permissions = permissionRepository.findAll(); 27 for (Permission permission : permissions) { 28 info.addStringPermission(permission.getKeyword()); 29 } 30 }else { 31 List<Role> roles =roleRepository.findbyUid(user.getId()); 32 for (Role role : roles) { 33 info.addRole(role.getKeyword()); 34 } 35 List<Permission> permissions = permissionRepository.findbyUid(user.getId()); 36 for (Permission permission : permissions) { 37 info.addStringPermission(permission.getKeyword()); 38 } 39 } 40 41 return info; 42 } 43 //认证的方法 44 @Override 45 protected AuthenticationInfo doGetAuthenticationInfo( 46 AuthenticationToken authenticationToken) throws AuthenticationException { 47 48 UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken; 49 String username = usernamePasswordToken.getUsername(); 50 //根据用户名查找用户 51 User user = userRepository.findByUsername(username); 52 if (user != null){ 53 54 /*@param principal 当事人,主体,通常是从数据库中查询到的用户 55 * @param credentials 凭证,密码,是从数据库中查询出来的密码 56 * @param realmName the realm from where the principal and credentials were acquired.*/ 57 //找到 -> 对比密码 58 AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),getName()); 59 // 比对成功-> 执行后续的逻辑 60 // 比对失败-> 抛异常 61 return info; 62 } 63 //找不到 -> 抛异常 64 return null; 65 } 66 }
7、给对应的方法添加权限注解(一般在service层)
1 @RequiresPermissions("batchDel") 2 //在调用方法时,框架就会检查当前用户是否有对应的权限,如果有就放行,没有就抛异常,启用权限注解必须开启CGLib 3 @Override 4 public void batchDel(String ids) { 5 if(StringUtils.isNotEmpty(ids)){ 6 String[] strings = ids.split(","); 7 for (String string : strings) { 8 courierRepository.updateDelTagsById(Long.parseLong(string)); 9 } 10 } 11 }
8、给对应的jsp页面添加权限标签进行显示隐藏
<shiro:hasPermission name="courierAction_pageQuery"> { id : 'button-delete', text : '作废', iconCls : 'icon-cancel', handler : doDelete } </shiro:hasPermission>
9、一般页面的显示的逻辑是:根据用户所有拥有的角色和权限进行动态生成菜单,从而只显示用户可操作的页面。