Spring MVC + shiro的权限控制框架的搭建

一.权限的几个定义

subject:主体,表示系统的操作用户
资源:作为开发者,主要考虑的是细粒度的资源,也就是对于系统的界面点击权限;例如查看列表的按钮
角色:不同的角色有不同的权限;同样,不同的用户有可能多个角色;这就相当于有多对多的关系
设计数据库时,我们会采用admin管理员表,role角色表,permission权限表;以及中间多对多关系admin-role,role-permiss表等。

二.整合开发

1.在web.xml文件中添加shiroFilter拦截器

<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>

2.springmvc的配置文件

<!-- 启用shrio授权注解拦截方式 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
	<!-- 装配 securityManager -->
	<property name="securityManager" ref="securityManager"/>
	<!-- 配置登陆页面 -->
	<property name="loginUrl" value="/common/welcome.htm"/>
	<!-- 登陆成功后的一面 -->
	<property name="successUrl" value="/common/home.htm"/>
    <property name="unauthorizedUrl" value="/common/unauthorized.htm"/>
	<!-- 具体配置需要拦截哪些 URL, 以及访问对应的 URL 时使用 Shiro 的什么 Filter 进行拦截.  -->
	<property name="filterChainDefinitions">
		<value>
			<!--/common/login.htm=anon-->
			/common/welcome.htm=anon
			/common/login.htm=anon
			/image/** = anon
			/common/index.htm=perms[activity:list]
			/survey/question_analysis.htm=perms[survey:list]
			/message/edit_common_meesage.htm=perms[comsg:add]
			/message/edit_ori_meesage.htm=perms[orimsg:add]
			/post/manager_post_list.htm=perms[post:list]
			/post/manager_post_list.htm=perms[post:list]
			/post/manager_post_detail.htm=perms[post:detail]
			/register/count_register_user.htm=perms[registeruser:check]
		</value>
	</property>
</bean>
<bean id="myRealm" class="com.syezon.chuda.manager.realm.MyRealm">
	<property name="credentialsMatcher">
		<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
			<property name="hashAlgorithmName" value="SHA1"></property>
			<property name="hashIterations" value="1024"></property>
		</bean>
	</property>
</bean>
<!-- 配置 Shiro 的 SecurityManager Bean. -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
	<property name="realm" ref="myRealm"/>
</bean>
<!-- 配置 Bean 后置处理器: 会自动的调用和 Spring 整合后各个组件的生命周期方法. -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

容器启动以后会查找配置文件下面的id为shiroFilter的拦截器;与上面的web.xmlwen配置的名称必须相同,阅读过源码的应该知道具体是根据targetName进行匹配的。
对于登陆界面,登陆成功,未授权的配置在上面注释已经标记出来,至于我的为什么htm;因为公司使用VM模板驱动,这是接口的后缀,当然你也可以配置成html界面。
filterChainDefinitions是拦截链,anon表示不需要登陆就可以访问的界面,比如你的登陆界面,这里的配置顺序很有讲究,如果顺序不对,会导致配置不生效的情况。
relam可以说是权限框架的核心了,一般我们通过debug调试,当通过subject.login()方法登陆时,会发现会进入到自定义relam的doGetAuthenticationInfo()方法认证。返回info对象

3.自定义relam

public class MyRealm extends AuthorizingRealm {

    @Resource
    IAdminDao<Admin> adminDao;

    @Resource
    IAdminRoleDao<AdminRole> adminRoleDao;

    @Resource
    IRoleDao<Role> roleDao;

    @Resource
    IPermissionDao<Permission> permissionDao;

    @Resource
    IRolePermissionDao<RolePermission> rolePermissionDao;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
//        Object credentials = null;
        Map<String,Object> adminMap = new HashMap<>();
        adminMap.put("username", username);
        Admin admin = adminDao.getOneObject(adminMap);
        if (null != admin){
            ByteSource credentialsSalt = ByteSource.Util.bytes(username);
            return new SimpleAuthenticationInfo(username, admin.getPassword(), credentialsSalt, getName());
        }
        return null;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Object principal = principalCollection.getPrimaryPrincipal();
        Set<String> permissions = new HashSet<>();
        Map<String,Object> adminMap = new HashMap<>();
        adminMap.put("username", principal);
        Admin admin = adminDao.getOneObject(adminMap);
        if (null != admin){
            Map<String,Object> adminRoleMap = new HashMap<>();
            adminRoleMap.put("adminid", admin.getId());
            List<AdminRole> adminRoleList = adminRoleDao.select(adminRoleMap);
            if (null != adminRoleList && adminRoleList.size() > 0){
                for (AdminRole adminRole : adminRoleList){
                    Long roleid = adminRole.getRoleid();
                    Map<String,Object> rolePermissionMap = new HashMap<>();
                    rolePermissionMap.put("roleid", roleid);
                    List<RolePermission> rolePermissions = rolePermissionDao.select(rolePermissionMap);
                    if (null != rolePermissions && rolePermissions.size() > 0){
                        for (RolePermission rolePermission : rolePermissions){
                            Long permissionid = rolePermission.getPermissionid();
                            Map<String,Object> permissionMap = new HashMap<>();
                            permissionMap.put("id", permissionid);
                            Permission permission = permissionDao.getOneObject(permissionMap);
                            if (null != permission){
                                permissions.add(permission.getOperation());
                            }
                        }
                    }
                }
            }
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permissions);
        return info;
    }

我们通过继承AuthorizingRealm方法重写认证和授权两个方法,里面具体写我们的业务逻辑。
最终返回

ByteSource credentialsSalt = ByteSource.Util.bytes(username);
return new SimpleAuthenticationInfo(username, admin.getPassword(), credentialsSalt, getName());

这里主要用到了密码加密,在上面springmvc的配置文件中,我们用到credentialsMatcher,匹配器;通过对于原密码的1024次SHA1加密,最终结果和数据库密码(已加密)比对,如果相同,表示登陆成功。

控制层的登陆接口

UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
        }catch (UnknownAccountException ue){
            model.addAttribute("msg", "账号不存在");
            return "/common/login";
        }catch (IncorrectCredentialsException ie){
            model.addAttribute("msg", "用户名或者密码不正确");
            return "/common/login";
        }catch (AuthenticationException ae){
            model.addAttribute("msg", "未知错误");
            return "/common/login";
        }

shiro对于密码比对不正确这种情况会通过异常抛出;

说完登陆认证接下来说授权

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permissions);
        return info;

在自定义relam中通过集合将权限进行整合,返回一个info对象给shiro框架
上面springmvc的配置文件中已经配置了访问资源所需权限,如下
/post/manager_post_detail.htm=perms[post:detail]
也可以通过subject.isPermitted("activity:delete")这种编码实现认证。
至于注解,与以上结果相似,主要还是理解shiro权限控制的过程

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值