shiro框架的Jar包下载:https://pan.baidu.com/s/1GCeHV_5T4uP2rGZfUEwl3A 密码:bgr0
权限控制的方式:
方式一:通过过滤器或Struts2的拦截器实现权限控制
方式二:为Struts2的Action加入注解(标识),然后为Action创建代理对象;代理对象进行权限校验,校验通过后通过反射调用目标方法。
shiro框架可以进行认证、授权、会话管理、加密等。
shiro框架认证/授权流程:
web.xml(web核心配置文件,配置Spring提供的shiro过滤器):
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>MyWeb</display-name>
<!-- 配置spring框架提供的用于整合shiro框架的过滤器。(要在Struts2的过滤器前面配置) -->
<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>
<!-- 配置过滤器,解决hibernate延迟加载no-session的问题 -->
<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 通过上下文参数指定spring配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 配置spring框架的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置struts2的过滤器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
applicationContext.xml(Spring的核心配置文件):
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:soap="http://cxf.apache.org/bindings/soap"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://cxf.apache.org/bindings/soap
http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
">
<!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -->
<!-- ====================================================================== -->
<!-- 配置shiro框架的过滤器工厂对象。"shiroFilter"要和web.xml中配置的过滤器名保持相同 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 注入安全管理器对象 -->
<property name="securityManager" ref="securityManager"/>
<!-- 注入访问相关页面的URL -->
<property name="loginUrl" value="/login.jsp"/>
<property name="successUrl" value="/index.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/> <!-- 权限不足的错误提示页 -->
<!--注入URL拦截规则 -->
<property name="filterChainDefinitions">
<value>
/css/** = anon <!-- anon是过滤器的别名(简称)。 两个*表示递归所有层子目录 -->
/js/** = anon <!-- 过滤器有次序之分,依次匹配过滤器 -->
/images/** = anon
/validatecode.jsp* = anon
/login.jsp = anon
/userAction_login.action = anon
/page_base_staff.action = perms["staff-list"] <!-- 必须先认证(登录)后,才会进行授权(权限分配)。"staff-list"是自定义的权限名 -->
/* = authc <!-- authc表示是否已认证(已登录) -->
</value>
</property>
</bean>
<!-- 注册安全管理器对象 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm"/> <!-- 将Realm注入安全管理器 -->
</bean>
<!-- 注册realm -->
<bean id="bosRealm" class="com.xxx.bos.realm.BOSRealm"></bean>
</beans>
UserAction.java(Struts2的Action):
package com.xxx.bos.web.action;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.struts2.ServletActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.xxx.bos.domain.User;
import com.xxx.bos.service.IUserService;
import com.xxx.bos.utils.BOSUtils;
import com.xxx.bos.utils.MD5Utils;
import com.xxx.bos.web.action.base.BaseAction;
@Controller
@Scope("prototype")
public class UserAction extends BaseAction<User> {
/**
* 用户登录,使用shiro框架提供的方式进行认证操作
*/
public String login(){
//使用shiro框架提供的方式进行认证操作
Subject subject = SecurityUtils.getSubject();//获得当前用户对象,状态为"未认证"
//创建用户名密码令牌对象
AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),MD5Utils.md5(model.getPassword()));//创建用户名密码令牌对象
try{
//认证(登录) (和注入了Realm的安全管理器(SecurityManager)进行交互,认证)
subject.login(token); //登录失败(认证失败)就会抛异常
}catch(Exception e){ //如果抛异常说明登录失败(认证失败)。 没有该用户和用户密码错误抛出的异常是不同的,可以分开catch。
e.printStackTrace();
return LOGIN;
}
//没抛异常说明认证成功
User user = (User) subject.getPrincipal(); //返回的是实例化SimpleAuthenticationInfo()时的第一个参数
ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);
return HOME;
}
}
BOSRealm.java(继承AuthorizingRealm):
package com.xxx.bos.realm;
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 org.springframework.beans.factory.annotation.Autowired;
import com.xxx.bos.dao.IUserDao;
import com.xxx.bos.domain.User;
public class BOSRealm extends AuthorizingRealm{
@Autowired
private IUserDao userDao;
//认证方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("自定义的realm中认证方法执行了。。。。");
UsernamePasswordToken passwordToken = (UsernamePasswordToken)token;
//获得页面输入的用户名
String username = passwordToken.getUsername();
//根据用户名查询数据库中的密码
User user = userDao.findUserByUsername(username);
if(user == null){
//页面输入的用户名不存在
return null; //return null 说明认证失败,安全管理器(SecurityManager)就会抛异常
}
//简单认证信息对象 (参数一:要传给subject的内容(subject.getPrincipal()获取的内容)。参数二:数据库中的密码;参数三:类名"BOSRealm")
AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
//框架负责比对数据库中的密码和页面输入的密码是否一致
return info; //交给安全管理器(SecurityManager)去比对密码。比对不一致也会抛异常(认证失败)。
}
//授权方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//为用户授权 (可以根据登录用户,查询数据库来确定该用户所拥有的权限)
info.addStringPermission("staff-list"); //"staff-list"和applicationContext.xml(Spring配置文件)中配置的perms["staff-list"]中的名字对应。
//TODO 需要根据当前登录用户查询数据库,获取实际对应的权限
//获取当前登录用户的两种方式
//User user = (User) SecurityUtils.getSubject().getPrincipal();
//User user2 = (User) principals.getPrimaryPrincipal();
return info;
}
}
applicationContext.xml(Spring的核心配置文件)中的shiro过滤器: