权限控制
权限控制两种方式:
1.基于URL粗粒度(常用)
可以基于 Filter 实现
在数据库中存放 用户、权限、访问 URL 对应关系, 当前用户访问一个 URL 地址,查
询数据库判断用户当前具有权限,是否包含这个 URL,如果包含允许访问,如果不包含
权限不足 !!!
2.基于方法细粒度(和钱有关的业务用的较多)
可以代理、自定义注解实现, 访问目标对象方法,在方法上添加权限注解信息,对目
标对象创建代理对象,访问真实对象先访问代理对象,在代理对象查询数据库判断是否具有
注解上描述需要权限,具有权限,允许访问,不具有权限,拦截访问,提示权限不足
权限控制的相关数据表结构(重点)
实体:用户,角色,权限
用户:系统登录用户
权限:描述权限信息(粗粒度权限控制,可能在权限表中描述访问资源URL信息)
角色:方便用户进行授权,角色就是权限的集合(主要作用就是方便我们进行权限赋值操作)
菜单:为了方便进行动态菜单管理 , 为不同用户定制不同系统菜单不同用户系统菜单,可以
根据用户角色 进行管理
角色 * --- * 菜单 之间的关系多对多
用户-----角色-----权限 之间的表关系都是多对多关系
ApacheShiro框架
是一款分厂好的开源的安全框架
1.体系结构
1> Authentication 认证 ---- 用户登录,身份识别 who are you?
2> Authorization 授权 --- 用户具有哪些权限、角色 what can you do ?
3> Cryptography 安全数据加密
4> Session Management 会话管理
5> Web Integration web 系统集成
6> Interations 集成其它应用,spring、缓存框架
Shiro运行流程
applicationCode----->Subject----->ShiroSecurityManager----->Reain
#applicationCode:编写代码(程序员写)
Subject:即“当前操作用户” 接受请求(方法参数)和参数(参数) ,将这些请求和数据交给SecurityManager
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务
#Realn:充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息 (程序员写)
Shiro进行权限控制
Shiro进行权限控制四种方式;
1.硬编码完成权限控制(耦合度高 不用)
2.URL粗粒度权限控制(掌握)
3.methode细粒度权限控制(了解)
4.页面通过自定义标签完成权限控制(了解)
URL级别的权限控制步骤(基于用户登录案例)
1.倒jar包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.3</version>
</dependency>
2.在web.xml中配置Shiro的filter过滤器
<filter>
<!-- 去spring配置文件中寻找同名bean -->
<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.配置application.xml配置文件
<!-- 配置Shiro核心Filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 安全管理器 -->
<property name="securityManager" ref="securityManager" />
<!-- 未认证,跳转到哪个页面 -->
<property name="loginUrl" value="/login.html" />
<!-- 登录页面页面 -->
<property name="successUrl" value="/index.html" />
<!-- 认证后,没有权限跳转页面 -->
<property name="unauthorizedUrl" value="/unauthorized.html" />
<!-- shiro URL控制过滤器规则 -->
<property name="filterChainDefinitions">
<value>
<!-- 过滤器简称:
anon 未认证可以访问
authc 认证后可以访问
perms 需要特定权限才能访问
roles 需要特定角色才能访问
user 需要特定用户才能访问
port 需要特定端口才能访问
reset 根据指定 HTTP 请求访问才能访问 -->
/login.html* = anon
/user_login.action* = anon
/validatecode.jsp* = anon
/css/** = anon
/js/** = anon
/images/** = anon
/services/** = anon
/pages/base/courier.html* = perms[courier:list]
/pages/base/area.html* = roles[base]
/** = authc
</value>
</property>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm" />
<property name="cacheManager" ref="shiroCacheManager" />
</bean>
<!-- 配置Realm -->
<bean id="bosRealm" class="cn.itcast.bos.realm.BosRealm">
<!-- 缓存区的名字 就是 ehcache.xml 自定义 cache的name -->
<property name="authorizationCacheName" value="bos" />
</bean>
<bean id="lifecycleBeanPostProcessor"class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 开启shiro注解模式 -->
<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>
4.前端页面设置form表单的action,给登录按钮添加点击事件
5.编写action
5.编写action
package cn.itcast.bos.web.action.system;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.beans.factory.annotation.Autowired;
import cn.itcast.bos.domain.system.User;
import cn.itcast.bos.web.action.common.BaseAction;
public class LoginAction extends BaseAction<User> {
@Autowired
private LoginService loginService;
@Action(value="user_login",results={@Result(name="success",type="redirect",location="index.html"),
@Result(name="login",type="redirect",location="login.html")})
public String login(){
//基于Shiro实现登陆
Subject subject = SecurityUtils.getSubject();
//获取用户名和密码信息
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(model.getPassword(),model.getUsername());
try {
//登录成功
subject.login(usernamePasswordToken);
return SUCCESS;
} catch (Exception e) {
// TODO: handle exception
//登录失败
return LOGIN;
}
return null;
}
}
6.编写realm继承AuthorizingRealm
@Service
public class BosRealm extends AuthorizingRealm {
//授权管理
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
// TODO Auto-generated method stub
System.err.println("授权管理--------------------");
return null;
}
//认证管理
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
// TODO Auto-generated method stub
System.err.println("认证管理--------------------");
return null;
}
7.给realm上添加一个@service注解,再将realm注入到安全管理器,才能实现安全管理器调用realm(action中调用Subject的login方法,login方法去调用安全管理器,安全管理器区调用realm,)
<!-- 安全管理器 -->
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm" />
<property name="cacheManager" ref="shiroCacheManager" />
</bean>
//认证管理
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// TODO Auto-generated method stub
System.err.println("认证管理--------------------");
//转换token
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
//根据用户名查询
User user = userService.findByUsername(usernamePasswordToken.getUsername());
if (user == null) {
//用户名不存在
return null;
} else {
//用户名存在
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
}
用户授权
//授权管理
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection ls) {
// TODO Auto-generated method stub
System.err.println("授权管理--------------------");
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//根据当前登录用户查询该用户的角色和授权
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
//调用业务层service,查询角色
List<Role> roles = roleService.findByUser(user);
//遍历角色集合
for (Role role : roles) {
simpleAuthorizationInfo.addRole(role.getKeyword());
}
//调用业务层service,查询权限
List<Permission> permissions = permissionService.findByPermission(user);
//遍历权限集合
for (Permission permission : permissions) {
simpleAuthorizationInfo.addStringPermission(permission.getKeyword());
}
return simpleAuthorizationInfo;
}