008-shiro与spring web项目整合【二】认证、授权、session管理
一、认证
1、添加凭证匹配器
添加凭证匹配器实现md5加密校验。
修改applicationContext-shiro.xml:
<!-- realm --> <bean id="customRealm" class="com.lhx.ssm.shiro.CustomRealm"> <!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 --> <property name="credentialsMatcher" ref="credentialsMatcher"/> </bean> <!-- 凭证匹配器 --> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="md5"/> <property name="hashIterations" value="1"/> </bean>
2、修改realm认证方法
修改realm代码从数据库中查询用户身份信息,将sysService注入realm。
public class CustomRealm extends AuthorizingRealm { //注入service @Autowired private SysService sysService; // 设置realm的名称 @Override public void setName(String name) { super.setName("customRealm"); } // 支持什么类型的token @Override public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; } // 用于认证 //realm的认证方法,从数据库查询用户信息 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { // token是用户输入的用户名和密码 // 第一步从token中取出用户名 String userCode = (String) token.getPrincipal(); // 第二步:根据用户输入的userCode从数据库查询 SysUser sysUser = null; try { sysUser = sysService.findSysUserByUserCode(userCode); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // 如果查询不到返回null if(sysUser==null){// return null; } // 从数据库查询到密码 String password = sysUser.getPassword(); //盐 String salt = sysUser.getSalt(); // 如果查询到返回认证信息AuthenticationInfo //activeUser就是用户身份信息 ActiveUser activeUser = new ActiveUser(); activeUser.setUserid(sysUser.getId()); activeUser.setUsercode(sysUser.getUsercode()); activeUser.setUsername(sysUser.getUsername()); //.. //根据用户id取出菜单 List<SysPermission> menus = null; try { //通过service取出菜单 menus = sysService.findMenuListByUserId(sysUser.getId()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //将用户菜单 设置到activeUser activeUser.setMenus(menus); //将activeUser设置simpleAuthenticationInfo SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( activeUser, password,ByteSource.Util.bytes(salt), this.getName()); return simpleAuthenticationInfo; } // ……授权下一个 }
二、授权
1.修改realm授权方法
修改realm代码从数据库中查询权限信息,将sysService注入realm
public class CustomRealm extends AuthorizingRealm { //注入service @Autowired private SysService sysService; // 设置realm的名称 @Override public void setName(String name) { super.setName("customRealm"); } // 支持什么类型的token @Override public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; } // 用于认证 //realm的认证方法,从数据库查询用户信息 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { // token是用户输入的用户名和密码 // 第一步从token中取出用户名 String userCode = (String) token.getPrincipal(); // 第二步:根据用户输入的userCode从数据库查询 SysUser sysUser = null; try { sysUser = sysService.findSysUserByUserCode(userCode); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // 如果查询不到返回null if(sysUser==null){// return null; } // 从数据库查询到密码 String password = sysUser.getPassword(); //盐 String salt = sysUser.getSalt(); // 如果查询到返回认证信息AuthenticationInfo //activeUser就是用户身份信息 ActiveUser activeUser = new ActiveUser(); activeUser.setUserid(sysUser.getId()); activeUser.setUsercode(sysUser.getUsercode()); activeUser.setUsername(sysUser.getUsername()); //.. //根据用户id取出菜单 List<SysPermission> menus = null; try { //通过service取出菜单 menus = sysService.findMenuListByUserId(sysUser.getId()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //将用户菜单 设置到activeUser activeUser.setMenus(menus); //将activeUser设置simpleAuthenticationInfo SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( activeUser, password,ByteSource.Util.bytes(salt), this.getName()); return simpleAuthenticationInfo; } // 用于授权 @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { //从 principals获取主身份信息 //将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型), ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal(); //根据身份信息获取权限信息 //从数据库获取到权限数据 List<SysPermission> permissionList = null; try { permissionList = sysService.findPermissionListByUserId(activeUser.getUserid()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //单独定一个集合对象 List<String> permissions = new ArrayList<String>(); if(permissionList!=null){ for(SysPermission sysPermission:permissionList){ //将数据库中的权限标签 符放入集合 permissions.add(sysPermission.getPercode()); } } /* List<String> permissions = new ArrayList<String>(); permissions.add("user:create");//用户的创建 permissions.add("item:query");//商品查询权限 permissions.add("item:add");//商品添加权限 permissions.add("item:edit");//商品修改权限 */ //.... //查到权限数据,返回授权信息(要包括 上边的permissions) SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //将上边查询到授权信息填充到simpleAuthorizationInfo对象中 simpleAuthorizationInfo.addStringPermissions(permissions); return simpleAuthorizationInfo; } }
2、对controller开启aop
在springmvc.xml中配置shiro注解支持,可在controller方法中使用shiro注解配置权限:
<!-- 开启aop,对类代理 --> <aop:config proxy-target-class="true"></aop:config> <!-- 开启shiro注解支持 --> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean>
3、权限注解控制
商品查询controller方法添加权限(item:query):
// 查询商品列表 @RequestMapping("/queryItem") @RequiresPermissions("item:query") public ModelAndView queryItem() throws Exception {
上边代码@RequiresPermissions("item:query")表示必须拥有“item:query”权限方可执行。
同理,商品修改controller方法添加权限(item:update):
@RequestMapping(value = "/editItem") @RequiresPermissions("item:update") public String editItem(@RequestParam(value = "id", required = true) Integer id, Model model) throws Exception
商品提交
// 商品修改提交 @RequestMapping("/editItemSubmit") @RequiresPermissions("item:update") public String editItemSubmit(@ModelAttribute("item") Items items,BindingResult result,MultipartFile pictureFile,Model model,HttpServletRequest request) throws Exception
4、jsp标签控制
4.1、标签简介
a、Jsp页面添加:
<%@ tagliburi="http://shiro.apache.org/tags" prefix="shiro" %>
b、详细
标签名称 |
标签条件(均是显示标签内容) |
<shiro:authenticated> |
登录之后 |
<shiro:notAuthenticated> |
不在登录状态时 |
<shiro:guest> |
用户在没有RememberMe时 |
<shiro:user> |
用户在RememberMe时 |
<shiro:hasAnyRoles name="abc,123" > |
在有abc或者123角色时 |
<shiro:hasRole name="abc"> |
拥有角色abc |
<shiro:lacksRole name="abc"> |
没有角色abc |
<shiro:hasPermission name="abc"> |
拥有权限资源abc |
<shiro:lacksPermission name="abc"> |
没有abc权限资源 |
<shiro:principal> |
显示用户身份名称 |
<shiro:principal property="username"/> 显示用户身份中的属性值
4.2、jsp页面添加标签
如果有商品修改权限页面显示“修改”链接。
<shiro:hasPermission name="item:update"> <a href="${pageContext.request.contextPath }/item/editItem.action?id=${item.id}">修改</a> </shiro:hasPermission>
三、session管理
和shiro整合后,使用shiro的session管理,shiro提供sessionDao操作 会话数据。
<!-- securityManager安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="customRealm"/> <!-- 注入session管理器 --> <property name="sessionManager" ref="sessionManager"/> </bean> <!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!-- session的失效时长,单位毫秒 --> <property name="globalSessionTimeout" value="600000"/> <!-- 删除失效的session --> <property name="deleteInvalidSessions" value="true"/> </bean>