一. 前期准备
一.一 数据库准备
数据库仍然使用的是 rbac数据库, 将 privilage 表数据改变一下, 为 菜单网址也添加 percode 属性。
一.二 前端页面准备
与前面基本一致 。
一.三 SSM框架准备
web.xml 和依赖,都需要添加。
二. SSM 整合Shiro 实现RBAC
通过 SSM 整合Shiro, 就是将 以前 shiro.ini 里面的配置内容,放置到 spring.xml 配置文件里面,
同样,要注入自定义的Realm, 设置securityManager,密码, 过滤器等内容。
但 spring整合 Shiro, 远比利用 shiro.ini 配置文件功能强大得多。
为了比较区别, 将上一章节的 shiro.ini 配置文件拿过来
[main] #加密类 credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher #加密方式 credentialsMatcher.hashAlgorithmName=md5 #加密次数 credentialsMatcher.hashIterations=10 #存储散列后的密码是否为16进制 credentialsMatcher.storedCredentialsHexEncoded=false #配置自定义realm myRealm=com.yjl.shiro.MyRealm #配置加密 myRealm.credentialsMatcher=$credentialsMatcher #注入自定义的realm securityManager.realm=$myRealm #配置权限 authc.loginUrl=/User/toLogin #跳转到权限不足的路径 roles.unauthorizedUrl=/NoPermission/NoPermission perms.unauthorizedUrl=/NoPermission/NoPermission [urls] #静态页面可以访问 /static/**=anon #跳转到登录页面和登录方法可以访问 /User/toLogin=anon /User/login=anon #跳转到主页,需要认证 /Main/toMain=authc /Privilege/getPrivilegeByUId=authc #执行方法,不仅需要认证,还需要有相应的方法 /Dept/add=authc,perms["dept:add"] /Dept/update=authc,perms["dept:update"] /Dept/list=authc,perms["dept:list"] /Dept/delete=authc,perms["dept:delete"] /User/toList=authc,perms["user:toList"] #退出登录 /User/logout=logout #其他的一切资源,都需要认证 /**=authc
二.一 添加 pom.xml 依赖
相比较以前,只多了一个 shiro-all 的依赖信息。
<!-- shiro依赖 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-all</artifactId> <version>1.2.2</version> </dependency>
二.二 web.xml 配置过滤器
<!-- 配置shiro 的过滤器 ,注意 filter-name的名称--> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <!-- 配置生命周期,由web控制 --> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> <!--一般不配置 targetBeanName参数,默认与filter-name 相同即可 --> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
二.三 编写后端代码
目录结构如下:
与前面的基本一致,没有太大的改动。
二.三.一 PrivilgeMapper 信息
注意, PrivilegeMapper.java 和 对应的 .xml 文件里面 仍然有一个根据员工编号和类型查询员工的权限方法
/* * 根据员工编号,查询员工的权限信息 * */ List<Privilege> findByUid(@Param(value="uId") Integer uId,@Param(value="type") Integer type);
对应 xml配置文件:
<select id="findByUid" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from privilege a where a.id in ( select rp.pid from user_role ur left join role_privilege rp on ur.rid=rp.rid where ur.uid=#{uId,jdbcType=INTEGER} ) <if test="type != null and type !=''" > and a.type=#{type,jdbcType=INTEGER} </if> </select>
这也是与前面一样的, 比较重要,故单独列一下。
二.三.二 登录和注销功能
@RequestMapping("/login") @ResponseBody public Map<String,Object> login(User userInfo){ Map<String,Object> dataMap=new HashMap<String,Object>(); //1. 获取 Subject Subject subject=SecurityUtils.getSubject(); //2. 配置Token //配置用户名和密码 UsernamePasswordToken token=new UsernamePasswordToken(userInfo.getCode(), userInfo.getPassword()); try{ //进行登录 subject.login(token); Session session=subject.getSession(); User user=(User)subject.getPrincipal(); session.setAttribute("loginUser", user); dataMap.put("response_status",true); }catch(Exception e){ e.printStackTrace(); dataMap.put("response_status",false); dataMap.put("error_msg","001"); } return dataMap; } @RequestMapping("/logout") //退出登录 public String logout(HttpSession session){ //注销 session.invalidate(); return "login"; }
二.四 编写自定义 Realm
这个跟前面也一样, 路径为: com.yjl.shiro.MyRealm
package com.yjl.shiro; import java.util.List; 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.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import org.springframework.beans.factory.annotation.Autowired; import com.yjl.mapper.PrivilegeMapper; import com.yjl.mapper.UserMapper; import com.yjl.pojo.Privilege; import com.yjl.pojo.User; public class MyRealm extends AuthorizingRealm{ @Autowired private UserMapper userMapper; @Autowired private PrivilegeMapper privilegeMapper; @Override public String getName() { return "myRealm"; } //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection paramPrincipalCollection) { //获取当前的登录用户 System.out.println("获取权限"); User user=(User)paramPrincipalCollection.getPrimaryPrincipal(); if(user==null){ return null; } //根据 id,获取相应的权限信息 List<Privilege> privilegeList=privilegeMapper.findByUid(user.getId(),null); SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(); for(Privilege priInfo:privilegeList){ //仍然放置的是权限的标识 , 注意,这儿获取的是所有的非一级 权限,包括菜单和按钮。 if(priInfo!=null&&priInfo.getPercode()!=null){ info.addStringPermission(priInfo.getPercode()); } } return info; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken paramAuthenticationToken) throws AuthenticationException { System.out.println("进入认证"); String code=(String)paramAuthenticationToken.getPrincipal(); //根据用户名,去查询相应的数据 User user=userMapper.selectInfoByCode(code); if(user==null){ //没有查询出来 return null; } SimpleAuthenticationInfo simpleAuthenticationInfo= new SimpleAuthenticationInfo(user,user.getPassword(), //传入转换后的盐 ByteSource.Util.bytes(user.getSalt()),getName()); return simpleAuthenticationInfo; } }