ssm搭建shrio安全框架(动态加载)
描述:
下面实现例子,实现简单,权限只控制到模块,模块勾选,模块下的功能全部通过。
其实要控制到方法,只需要添加一些标记字符即可。
一、 shrio介绍
二、导入jar包
三、Web.Xml配置
四、Shrio.xml 配置
五、重点实现shiro配置的内容(必须)
六、根据需求实现shiro配置
七、java文件和配置下载
一、shrio简单介绍
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
框架图:
1、Subject:当前操作用户
2、SecurityManager :安全管理器,Shiro框架的核心组件,管理所有Subject。
内部组成:
Authenticator(登录认证)。
Authorizer(访问授权)。
Session Manager(创建和管理用户Session生命周期)。
Session Dao(操作session数据,可重写AbstractSessionDAO对
session实现增删查改操作)。
CacheManager(缓存Shiro使用的鉴权数据)。
3、Realms:领域,用于进行权限信息的验证(实现Authenticator和Authorizer)
详细解析参考其他博客。
二、导入jar包
版本号
<shiro.version>1.3.2</shiro.version>
<!—shiro相关jar包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
三、Web.Xml配置
<filter>
<!--与shiro.xml里org.apache.shiro.spring.web.ShiroFilterFactoryBean的bean
name相同 -->
<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>
四、Shrio.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:jee="http://www.springframework.org/schema/jee"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"
default-lazy-init="true">
<!-- Shiro 拦截 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- shiro的核心安全接口 -->
<property name="securityManager" ref="securityManager" />
<!-- 登录时的链接 -->
<property name="loginUrl" value="/jsp/login.jsp" />
<!-- 登录成功时,跳转的链接 -->
<property name="successUrl" value="/jsp/Main.jsp" />
<!-- 未认证时跳转的链接 -->
<!-- <property name="unauthorizedUrl" value="/jsp/login.jsp" /> -->
<property name="filters">
<!-- 添加链接key规则,系统默认key有:anon(无需权限),authc(登录后可访问),perms(需要指定的权限),roles(需要指定角色)等,还可以自定义key -->
<map>
<!--系统默认key-->
<entry key="authc">
<bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
</entry>
<!--重写perms-->
<entry key="perms">
<!--继承PermissionsAuthorizationFilter进行重写-->
<bean class="重写权限类"></bean>
</entry>
<!--自定义key
<entry key="填写自定义key">
<bean class="指向指定类"></bean>
</entry>
-->
</map>
</property>
<!--配置拦截链接-->
<property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" />
</bean>
<!--加载拦截链接-->
<bean id="chainDefinitionSectionMetaSource" class="拦截连接实现类"></bean>
<!-- 安全接口 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userAuthorization" />
</bean>
<!-- 登录认证、授权 -->
<bean id="userAuthorization" class="登录授权认证实现类">
</bean>
<!-- 使用springmvc HandlerExceptionResolver接口处理shiro异常 -->
<bean class="异常拦截"></bean>
</beans>
五、重点实现shiro.xml配置的内容(必须)
(1)实现AuthorizingRealm类(登录授权认证实现类)
实现shiro.xml中配置
<!-- 登录认证、授权 -->
<bean id="userAuthorization" class="登录授权认证实现类">
doGetAuthorizationInfo 访问需要权限链接时进入(授权)
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pCollection) {
//用户授权
String userName = SecurityUtils.getSubject().getPrincipal().toString();
if (!StringUtils.isEmpty(userName)) {
//获取用户权限字符串
String[] actionList ={};
for (String str : actionList) {
//设置用户权限
info.addStringPermission(str);
}
//返回权限信息
return info;
}
return null;
}
doGetAuthenticationInfo 用户登录时进入(验证)
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//用户认证
UsernamePasswordToken uPasswordToken = (UsernamePasswordToken) token;
String userName = uPasswordToken.getUsername();
char[] c = uPasswordToken.getPassword();
if (userName == null || userName.equals("") || c == null ||c.length==0) {
//用户名或密码为空,直接退出
return null;
}
//这里查询用户,处理业务需求
UserAuthority userAuthority=new UserAuthority();
userAuthority.setUserName(“aaa”);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userAuthority, passwork,getName());
return info;
}
UserAuthority 类解释
定义所需保存的数据(根据自己需求定义一个类即可)
如何doGetAuthenticationInfo登陆验证
public Object login(String userName, String passwork) {
//获取主体
Subject subject=SecurityUtils.getSubject();
AuthenticationToken token=new UsernamePasswordToken(username, password);
//开始认证
subject.login(token);
//获取用户认证
boolean bool=subject.isAuthenticated();
System.out.println("认证成功:"+bool);
ModelAndView mv = new ModelAndView();
if (bool) {
return "redirect:/jsp/Main.jsp";
} else {
return "redirect:/jsp/login.jsp";
}
}
当前台点击登录时,访问login方法,获取主体,并设置用户密码令牌,当代码执行到
subject.login(token)时触发doGetAuthenticationInfo方法,并得到的令牌AuthenticationToken ,因为得到的令牌是登录时设置的用户密码令牌,因此将该令牌token转回UsernamePasswordToken。接着查询数据库获取用户,并将查询到的用户信息设置到SimpleAuthenticationInfo,并返回SimpleAuthenticationInfo。紧接着继续执行subject.login(token)后的方法。
(2)设置整个系统的所有权限
实现shrio.xml中的
<!--加载拦截链接-->
<bean id="chainDefinitionSectionMetaSource" class="拦截连接实现类"></bean>
利用spring的FactoryBean<Ini.Section>动态获取数据库保存的链接,
实现方法getObject(),该方法会在spring容器加载时触发。
private StringBuffer filter = new StringBuffer();
public static final String PREMISSION_STRING = " = authc,perms[\"{0}\"]\n";
public Section getObject() {
//添加字符串格式:url=key,如url=authc,perms["权限字符串"]
filter.append("/jsp/login.jsp=anon\n");//这里\n必须写上,防止拼接成一行,导致Ini.Section解释成一条链接
//这里完成权限字符串获取,拼接(数据库查询)
filter.append("");
Ini ini = new Ini();
ini.load(fiter);
Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
return section;
}
为什么使用类Ini.Section?
从org.apache.shiro.spring.web.ShiroFilterFactoryBean类中,
可以看出filterChainDefinitionMap属性的类型是Map<String,String>,
因此继承FactoryBean<>的泛型必须为Map<String,String>或者它的子类,
Ini.Section是shrio对Map<String,String>的封装,
也可以写成FactoryBean<Map<String,String>>,
key为url,value为权限字符(authc,perms["权限字符串"])
ShiroFilterFactoryBean类
Ini.Section类
六、根据需求实现shiro配置
剩下Shrio.xml中没实现的就是按自己需求来配置
(1)PermissionsAuthorizationFilter重写(权限字符串重写)
重写shrio.xml中的
引入重写内容,在shiro拦截器中加入filters属性
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="filters">
<map>
<entry key="perms">
<bean class="重写权限类"></bean>
</entry>
</map>
</property>
</bean>
原来的拦截方式:
(如果长度为1,判断是否有改权限字符串,长度不为1判断是否拥有所有的权限字符串,
如:/url= authc,perms[“12”,”21”],当访问/url时,就必须拥有”12”,”21”,这两个字符串)
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
Subject subject = getSubject(request, response);
String[] perms = (String[]) mappedValue;
boolean isPermitted = true;
if (perms != null && perms.length > 0) {
if (perms.length == 1) {
if (!subject.isPermitted(perms[0])) {
isPermitted = false;
}
} else {
if (!subject.isPermittedAll(perms)) {
isPermitted = false;
}
}
}
return isPermitted;
}
重写后的拦截方式(只需判断是否拥有其中一个权限字符串就可以访问,
如/url= authc,perms[“12”,”21”],当访问/url时,拥有”12”或”21”就可以访问 )
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
Subject subject = getSubject(request, response);
String[] perms = (String[]) mappedValue;
if (perms != null && perms.length > 0) {
boolean[] bs = subject.isPermitted(perms); //返回判断数组
for (boolean b : bs) {
if(b){
//说明有权限,直接返回
return true;
}
}
}
return false;
}
(2)异常拦截
重写shiro.xml配置文件
引入重写内容,在shiro.xml文件,直接追加bean
<!-- 使用springmvc HandlerExceptionResolver接口处理shiro异常 -->
<bean class="异常拦截"></bean>
当访问链接时出现异常如何处理
实现springmvc的HandlerExceptionResolver异常处理
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object object,Exception ex){
ex.printStackTrace();
if(ex instanceof UnauthorizedException) {
//没有认证
System.out.println("没有认证");
ModelAndView mv = new ModelAndView("redirect:/jsp/login.jsp");
return mv;
}else if(ex instanceof UnknownAccountException||ex instanceof AuthenticationException) {
//登录过期没有权限 跳回登录页面
System.out.println("登录过期");
ModelAndView mv = new ModelAndView("redirect:/jsp/login.jsp");
mv.addObject("Result", "您需要登录");
return mv;
} else if(ex instanceof HostUnauthorizedException){
System.out.println("没有接口权限");
return new ModelAndView("exception/noPermission");
}
return null;
}
标题1中介绍的SecurityManager 剩下内容
Session Manager(创建和管理用户Session生命周期)。
CacheManager(缓存Shiro使用的鉴权数据)。
如有需要继续往下面配置中添加即可。
<!-- 安全接口 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userAuthorization" />
<!--需要添加-->
</bean>
这里就不配置了。