权限控制
常见的权限控制
1\URL 拦截权限控制
通过拦截器或者过滤器拦截客户端发送的请求,在拦截器或者过滤器中判断当前用户是否具有访问权限有就放行,没有权限 跳转到权限不足的提示页面
2\方法注解权限控制
基于代理技术实现 有代理对象进行权限校验
权限数据模型
1\权限表
2\角色表
就是权限的集合
3\用户表
4\角色权限关系表
5\用户角色关系表
shrio
核心功能
1\认证
2\授权
3\会话管理
4\加密
Authentication:身份认证 / 登录,验证用户是不是拥有相应的身份;
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
maven 引用:
<!-- shiro依赖包 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-cas</artifactId> <version>1.2.3</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-quartz</artifactId> <version>1.2.3</version> </dependency> <!-- shiro end -->
Application Code
应用程序代码 开发人员开发
Subject
框架提供的接口 代表当前用户对象
SecurityManager
框架提供的接口 代表安全管理器对象 ***********
Realm
开发人员可以编写,框架也提供一些 类似DAO 用于访问权限数据
使用
1\在项目中引入maven 依赖
2\在web.xml 配置一个过滤器
<filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3\在spring 配置文件中配置beanid和上面的过滤器的名称一样
<!-- 配置shiro 框架的过滤器工厂对象 -->
<bean name="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" > <!-- 注入安全管理器对象 --> <property name="securityManager" ref="securityManager"></property> <!-- 注入登录页面 --> <property name="loginUrl" value="/index.jsp"></property> <!-- 注入登录成功页面 --> <!-- <property name="successUrl" value="/index.jsp"></property> --> <!-- 注入无权限页面 --> <property name="unauthorizedUrl" value="/error.jsp"></property> <!-- 注入URL拦截规则 --> <property name="filterChainDefinitions"> <value> /css/** = anon<!--css 放行 --> /js/** = authc<!-- js放行 --> /images/** = anon<!-- 图片放行 --> /validatecode.jsp* = anon<!-- 验证码放行 --> /index.jsp = anon<!-- 主页放行 --> /toLogin.do = anon<!-- 去登录页面请求 --> /user/login.do = anon<!-- 登录请求 --> /user/** = perms["user-list"]<!-- staff的一切请求 --> /page.do = perms["page-list"]<!-- staff的一切请求 --> /* = authc <!-- 其他的一切请求 --> </value> </property> </bean> <!-- 注册安全管理器对象 --> <bean name="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- 注入realm --> <property name="realm" ref="bosRealm"></property> </bean> <!-- 注册realm --> <bean name="bosRealm" class="com.stevezong.bos.realm.BosRealm"></bean>
过滤器名称过滤器类描述
anonorg.apache.shiro.web.filter.authc.AnonymousFilter匿名过滤器
authcorg.apache.shiro.web.filter.authc.FormAuthenticationFilter当前用户是否已经登录
authcBasicorg.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter基本http验证过滤,如果不通过,跳转屋登录页面
logoutorg.apache.shiro.web.filter.authc.LogoutFilter登录退出过滤器
noSessionCreationorg.apache.shiro.web.filter.session.NoSessionCreationFilter没有session创建过滤器
permsorg.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter权限过滤器
portorg.apache.shiro.web.filter.authz.PortFilter端口过滤器,可以设置是否是指定端口如果不是跳转到登录页面
restorg.apache.shiro.web.filter.authz.HttpMethodPermissionFilterhttp方法过滤器,可以指定如post不能进行访问等
rolesorg.apache.shiro.web.filter.authz.RolesAuthorizationFilter角色过滤器,判断当前用户是否指定角色
sslorg.apache.shiro.web.filter.authz.SslFilter请求需要通过ssl,如果不是跳转回登录页
userorg.apache.shiro.web.filter.authc.UserFilter如果访问一个已知用户,比如记住我功能,走这个过滤器
4\登录Controller
//使用shiro 框架提供的方式进行认证操作
Subject subject = SecurityUtils.getSubject();//获取当前用户对象,状态为:未认证
AuthenticationToken token = new UsernamePasswordToken(username, MD5Utils.md5(password));
try {
subject.login(token);
} catch (Exception e) {
e.printStackTrace();
result = "login";
}
user = (User) subject.getPrincipal();
session.setAttribute("user", user);
session.setMaxInactiveInterval(60*60*24);
result = "redirect:../pages_common_index.do";
5\写Realm
Exception 类型:
没有这个用户名
UnknownAccountException
密码错误
IncorrectCredentialsException
package com.stevezong.bos.realm;
import javax.annotation.Resource;
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.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import com.stevezong.bos.dao.UserMapper;
import com.stevezong.bos.entity.User;
public class BosRealm extends AuthorizingRealm{
@Resource
UserMapper userMapper;
//认证方法
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("自定义Realm");
//根据用户名查询数据库中的密码
//将AuthenticationToken 强转为 UsernamePasswordToken 方便使用
UsernamePasswordToken passwordToken = (UsernamePasswordToken) token;
//根据用户名查询数据中的User对象
User user = userMapper.findByUsername(passwordToken.getUsername());
if(user == null) {
//页面输入的用户名不存在
return null;
}else {
//简单认证信息对象(user对象,数据库中的密码,任意字符串)
AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
//框架负责对比数据库中的密码和页面输入的密码是否一致
return info;
}
}
//授权方法
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
// TODO 后期需要修改为根据当前登录永固查询数据库获取实际对应的权限
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("staff-list");
return info;
}
}
shiro 注解
1\
<!-- 开启shiro的注解支持 --> <bean id="defaultAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> <!-- 必须改为true,即使用cglib方式为Action创建代理对象。默认值为false,使用JDK创建代理对象,会造成问题 --> <property name="proxyTargetClass" value="true"></property> </bean> <!-- 使用shiro框架提供的切面类,用于创建代理对象 --> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"></bean>
2\在对应的方法上加上注解
@RequiresPermissions("权限名称")
package com.stevezong.bos.controller;
import javax.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.stevezong.bos.service.StaffService;
import com.stevezong.bos.utils.BosResult;
@Controller
@RequestMapping("/staff")
public class StaffDelController {
@Resource(name = "staffService")
StaffService staffService;
@RequestMapping("/del.do")
@ResponseBody
@RequiresPermissions("staff-delete")
public BosResult<Object> del(String ids){
BosResult<Object> result = new BosResult<Object>();
String[] idsArr = ids.split(",");
int[] resultArr = new int[idsArr.length];
for(int i = 0; i<idsArr.length;i++) {
resultArr[i] = staffService.updateDeltagById(idsArr[i]);
}
result.setStatus(0);
result.setMsg("修改完成");
result.setData(resultArr);
return result;
}
}
3\在ssm 框架中捕获shiro 的权限不足异常
shiro jsp 标签库
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
用户是否有这个权限
<shiro:hasPermission name="权限名">js,jsp,html 都可以</shiro:hasPermission>
<shiro:hasPermission name="staff-list">
{
id : 'button-delete',
text : '作废',
iconCls : 'icon-cancel',
handler : doDelete
},
</shiro:hasPermission>
权限数据管理
曾删改查
初始化权限数据
添加权限数据
权限分页查询