shiro详解:maven+spring+springmvc+mybatis+shiro项目的整合

1.当然是先建表

Create Table

CREATE TABLE `role` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `rolecode` varchar(255) DEFAULT NULL COMMENT '角色编码',
  `rolename` varchar(255) DEFAULT NULL COMMENT '角色名称',
  `remark` varchar(255) DEFAULT NULL COMMENT '说明信息',
  `status` int(11) DEFAULT NULL COMMENT '使用状态1在用/0弃用',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='角色表'





Create Table

CREATE TABLE `user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `user_id` int(11) DEFAULT NULL COMMENT '用户ID',
  `role_id` int(11) DEFAULT NULL COMMENT '角色ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='用户角色关系表'




Create Table

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `username` varchar(255) DEFAULT NULL COMMENT '用户昵称',
  `usercode` varchar(255) DEFAULT NULL COMMENT '员工工号',
  `password` varchar(255) DEFAULT NULL COMMENT '登录密码',
  `phone` varchar(255) DEFAULT NULL COMMENT '联系电话',
  `mark` varchar(255) DEFAULT NULL COMMENT '备注',
  `status` int(11) DEFAULT NULL COMMENT '使用状态1在用/0弃用',
  `lastlogin` datetime DEFAULT NULL COMMENT '最近一次登录时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='用户表'




Create Table

CREATE TABLE `resource` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `parentId` int(11) DEFAULT NULL COMMENT '上级资源ID',
  `resourcename` varchar(255) DEFAULT NULL COMMENT '资源名称',
  `url` varchar(255) DEFAULT NULL COMMENT '资源访问url',
  `resourcecode` varchar(255) DEFAULT NULL COMMENT '资源标识',
  `status` int(11) DEFAULT NULL COMMENT '使用状态1在用/0弃用',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='资源表'




Create Table

CREATE TABLE `role_resource` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `role_id` int(11) DEFAULT NULL COMMENT '角色ID',
  `resource_id` int(11) DEFAULT NULL COMMENT '资源ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='角色资源关系表'

这是五张表,因为没有外键关系,所以以后要用sql控制多对多的关系

2.贴一下自定义的拦截器

/**
 * 
 * JAVA Realm
 * 内部重写了用户认证与查询授权两个方法
 *
 * @author Administrator
 * @version 产品版本信息 Dec 1, 2017 姓名(邮箱) 修改信息
 */
public class MyRealm extends AuthorizingRealm
{
    @Autowired
    LoginService loginService;

    public MyRealm()
    {
    }

    // 授权 后台添加@RequiresPermissions的Controller
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
    {
        // 获取用户名
        User user = (User) principals.getPrimaryPrincipal();
        String usercode = user.getUsercode();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        try
        {
            // 手工指定 数据源 ,若开启事务控制设置,则需打开此代码
            /* DynamicDataSourceHolder.setDataSource("db_local_eventanalysis_test"); */
            // 获取角色下的权限,在这里查询出来的权限,与 @RequiresPermissions("resource:query")的resource:query作比较。如果权限集合中有resource:query这个标签就通过,不存在的话就转发到无权页面
            authorizationInfo.setStringPermissions(loginService.getPerms(usercode));
            System.out.println("usercode:" + usercode + " permission:" + authorizationInfo.getStringPermissions());

        }
        catch (SQLException e)
        {
            e.printStackTrace();
        } // 设置

        return authorizationInfo;
    }

    // 用户登录,用户身份认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
    {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String usercode = usernamePasswordToken.getUsername();
        String password = String.valueOf(usernamePasswordToken.getPassword());
        // password = CryptUtil.psdCrypt(password, usercode);
        User user = null;
        try
        {
            // 手工指定 数据源 若开启事务控制设置,则需打开此代码
            /* DynamicDataSourceHolder.setDataSource("db_local_eventanalysis_test"); */
            user = loginService.execute(usercode);
        }
        catch (SQLException e1)
        {
            e1.printStackTrace();
            System.out.println(e1);
            
        } // 验证员工工号是否存在
        if (user != null && password.equals(user.getPassword()))
        { // 验证密码是否匹配
            Calendar calendar = Calendar.getInstance();
            String lastlogin = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(calendar.getTime());
            user.setLastLogin(lastlogin);
            try
            {
                loginService.setLastLogin(user);// 更新最近一次登陆时间
            }
            catch (SQLException e)
            {
                e.printStackTrace();
            }
            // 保存用户信息
            return new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
        }
        else
        {
            throw new AuthenticationException();
        }
    }

}

3.配置文件

shiro.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
                        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd"
    default-lazy-init="true">

    <!-- 配置Realm,自己定义的myRealm,必须继承AuthorizingRealm -->
    <bean id="myRealm" class="com.travelsky.updateDatabase.shiro.MyRealm">
        <property name="cacheManager" ref="cacheManager" />
    </bean>

    <!-- 2. 配置cacheManager(缓存管理) -->
    <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
    <!-- 1. 配置securityManager,也就是shiro的核心。 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm" />
        <!-- 缓存管理器 -->
        <property name="cacheManager" ref="cacheManager" />
    </bean>

    <!-- <bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter"> 
         <property name="redirectUrl" value="/login/logout" /> </bean> -->
    <!-- 配置shiroFilter id必须和web.xml 文件中配置的DelegatingFilterProxy的filter-name一致 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全接口,这个属性是必须的 -->
        <property name="securityManager" ref="securityManager" />
        <!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
        <property name="loginUrl" value="/login/execute" />
        <!-- 登录成功后要跳转的连接 -->
        <property name="successUrl" value="/common/main.jsp" />
        <!-- 用户访问未对其授权的资源时,所显示的连接 -->
        <property name="unauthorizedUrl" value="/common/no_authority.jsp" />
        <!-- <property name="filters"> 
              <map> <entry key="logout" value-ref="systemLogoutFilter"/> </map> 
        </property> -->
        <!-- Shiro权限过滤过滤器定义 -->
        <property name="filterChainDefinitions">
            <value>
                <!-- 配置哪些页面需要受保护 以及访问这些页面需要的权限anon可以被匿名访问,或者说游客可以访问 authc必须认证之后才能访问,即登录后才能访问的页面 -->
                <!--  /logout=logout -->
            </value>
        </property>
    </bean>
   
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    <!-- AOP式方法级权限检查 -->
    <bean
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
        depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>
    <bean
        class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>
</beans>

3.首先是添加用户,shiro整合比较难的就是前期框架的搭建,用户要先在存入入数据库才能验证

<select id="findUserList" resultType="User" parameterType="User">
     SELECT 
        u.id,
        u.usercode,
        u.username,
        u.phone,
        u.lastlogin,
        r.rolename,
        u.mark
     FROM 
        user u 
        left join user_role ur on u.id = ur.user_id
        left join role r on ur.role_id = r.id 
     WHERE 
         1=1 
     AND 
       u.status=1
  <if test="username != null and username != '' ">
     AND 
      username=#{username}
  </if>
  <if test="usercode !=null and usercode != '' ">
     AND 
      usercode=#{usercode}
  </if>
    ORDER BY 
      id 
    DESC
  </select>



这个方法调用的是

doGetAuthenticationInfo的方法

在不同的路径下访问也会走这个方法shiro.xml

<!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
        <property name="loginUrl" value="/login/execute" />

4.添加资源

这里要先设置资源父节点


 <!-- 添加资源 -->
    <insert id="addResource" parameterType="resource">
       INSERT INTO resource(parentId,resourcename,url,resourcecode,status) 
           VALUES(#{parentId},#{resourcename},#{url},#{resourcecode},1)
    </insert>

5.添加角色

<!-- 添加角色 -->
	<insert id="addRole" parameterType="Role">
		INSERT INTO
		role
		(rolecode,rolename,remark,STATUS)
		VALUES
		(#{rolecode},#{rolename},#{remark},1)
	</insert>

重点:角色与资源关联,联系到role_rosource表

 /**
     * 为角色重新分配拥有的权限资源
     */
    @Override
    public boolean updateResourceByRoleid(String roleId, String resourceIds) throws SQLException
    {
        RoleResourceRelation relation = new RoleResourceRelation();
        relation.setRole_id(Integer.parseInt(roleId));
        roleDao.deleteRoleResourceRelationByRoleId(Integer.parseInt(roleId));
        String[] split = resourceIds.split(",");
        for (String str : split)
        {
            if (str != null && str != "")
            {
                relation.setResource_id(Integer.parseInt(str));
                roleDao.insertRoleResourceRelation(relation);
            }
        }

        return true;
    }

sql

<insert id="insertRoleResourceRelation" parameterType="RoleResourceRelation">
	   INSERT INTO
	   role_resource(role_id,resource_id)
	   VALUES(#{role_id},#{resource_id})
	</insert>

6.用户和角色的绑定

<insert id="insertUserRoleRelation" parameterType="UserRoleRelation">
    INSERT INTO 
        user_role ( user_id,   role_id)
        VALUE(  #{userId},    #{roleId})
  </insert>

总结:1.Controller层控制是否有权限@RequiresPermissions("role:view"),只要有这个标签,就是会走realm中的授权,这里面有我们在刚才登录时信息,从里面可以拿到我们的登录信息,获取到用户,然后从用户获取权限,将路径访问的方法 的role:view与数据库中的配置进行比较,没有匹配的将将会跳到无权显示中


2.前段设置权限显示:shiro会根据当前的用户的用户的权限和前段的字段进行比较,有匹配的就显示,没有的话就不显示


会自动走授权的方法!!不必纠结~

具体太细节的东西就不写了,因为要贴的东西太多了,这里是主要的配置,剩下的就是具体的代码了

每天进步一点点


猜你喜欢

转载自blog.csdn.net/qq_38788128/article/details/80604434