Shiro-Spring-Web
程序员文章站
2022-04-26 11:17:47
...
一、web.xml
<?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"
id="WebApp_ID" version="2.5">
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Shiro Filter is defined in the spring application context: -->
<!--
1. 配置 Shiro 的 shiroFilter.
2. DelegatingFilterProxy 实际上是 Filter 的一个代理对象. 默认情况下, Spring 会到 IOC 容器中查找和
<filter-name> 对应的 filter bean. 也可以通过 targetBeanName 的初始化参数来配置 filter bean 的 id.
-->
<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>
</web-app>
二、application.xml配置解析
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util" 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"
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/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
default-autowire="byName" default-lazy-init="false">
<!-- 1、相当于调用SecurityUtils.setSecurityManager(securityManager) -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
<property name="arguments" ref="securityManager"/>
</bean>
<!--2、安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm"/>
</bean>
<!--3、 自定义的user Realm实现 -->
<bean id="userRealm" class="com.bigpay.permission.shiro.realm.OperatorRealm">
<property name="credentialsMatcher" ref="credentialsMatcher" />
<property name="cachingEnabled" value="false" />
<!--<property name="authorizationCachingEnabled" value="true"/> -->
<!--<property name="authorizationCacheName" value="authorizationCache"/> -->
</bean>
<!-- 4、认证的时候 凭证匹配器,做登录次数验证,和密码匹配验证 -->
<bean id="credentialsMatcher"
class="com.bigpay.permission.shiro.credentials.RetryLimitHashedCredentialsMatcher">
<constructor-arg ref="cacheManager"/> <!-- 登录次数放入缓存 -->
<property name="hashAlgorithmName" value="md5"/> <!-- 密码 MD5加密 -->
<property name="hashIterations" value="2"/> <!-- 加密次数 -->
<property name="storedCredentialsHexEncoded" value="true"/>
</bean>
<!--5、 缓存管理器 -->
<bean id="cacheManager" class="com.bigpay.permission.shiro.spring.SpringCacheManagerWrapper">
<property name="cacheManager" ref="springCacheManager"/>
</bean>
<bean id="springCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManager"/>
</bean>
<!--ehcache -->
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:spring/permission/ehcache/ehcache.xml"/>
</bean>
<!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行 -->
<!-- Web应用中,Shiro可控制的Web请求必须经过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持
id 必须和 web.xml 文件中配置的 DelegatingFilterProxy 的 <filter-name> 一致.
若不一致, 则会抛出: NoSuchBeanDefinitionException. 因为 Shiro 会来 IOC 容器中查找和 <filter-name> 名字对应的 filter bean -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- 登录controller的mapper地址 -->
<property name="loginUrl" value="/login.jsp" /> <!-- shiro登录时跳转的地址 -->
<property name="successUrl" value="/list.jsp" /> <!-- shiro登录成功时跳转的地址 -->
<property name="unauthorizedUrl" value="/system/unauthorized.jsp" /><!-- shiro授权失败时跳转的地址 -->
<property name="filters">
<util:map>
<entry key="authc" value-ref="authcFilter" />
<entry key="rcCaptchaValidate" value-ref="rcCaptchaValidateFilter" />
</util:map>
</property>
<!--
配置哪些页面需要受保护.
以及访问这些页面需要的权限.
1). anon 可以被匿名访问(没有认证也可以访问)
2). authc 必须认证(即登录)后才可能访问的页面.
3). logout 登出.
4). roles 角色过滤器
-->
<property name="filterChainDefinitions">
<value>
<!-- Shiro的Web过滤器 -->
/rcCaptcha* = anon
/system/unauthorized.jsp = anon
/common/** = anon
/dwz/** =anon
/favicon.ico=anon
/login = rcCaptchaValidate,authc
/user.jsp = roles[user] <!-- user角色可以访问 -->
/admin.jsp = roles[admin]
/logout = logout <!-- shiro登出 -->
/** = authc
</value>
</property>
</bean>
<!-- Shiro生命周期处理器 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<!--
启用 IOC 容器中使用 shiro 的注解. 但必须在配置了 LifecycleBeanPostProcessor 之后才可以使用.
-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
</beans>
过滤器细节
[urls] 部分的配置,其格式是: “url=拦截器[参数],拦截器[参数]”;
anon(anonymous) 拦截器表示匿名访问(即不需要登录即可访问)
authc (authentication)拦截器表示需要身份认证通过后 才能访问
三、自定义realm
/**
* 自定义realm .
*/
public class OperatorRealm extends AuthorizingRealm {
@Autowired
private PmsOperatorService pmsOperatorService;
@Autowired
private PmsOperatorRoleService pmsOperatorRoleService;
@Autowired
private PmsRolePermissionService pmsRolePermissionService;
@Override// 认证核心方法 AuthenticationToken 是subject.login(token) 方法传过来的
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String loginName = (String) token.getPrincipal();
if (StringUtils.isEmpty(loginName.trim())) {
throw new UnknownAccountException();// 没找到帐号
}
// 根据登录名查询操作员
PmsOperator operator = pmsOperatorService.findOperatorByLoginName(loginName);
if (operator == null) {
throw new UnknownAccountException();// 没找到帐号
}
if (PublicStatusEnum.UNACTIVE.name().equals(operator.getStatus())) {
throw new LockedAccountException(); // 帐号锁定
}
//密码比对
//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现(如application.xml中定义的 MD5加密次数等)
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
operator.getLoginName(), // 登录名
operator.getLoginPwd(), // 密码
ByteSource.Util.bytes(operator.getCredentialsSalt()), //盐值
getName() // realm name
);
return authenticationInfo;
}
@SuppressWarnings("unchecked")
@Override//授权核心方法
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String loginName = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
PmsOperator operator = (PmsOperator) session.getAttribute("PmsOperator");
if (operator == null) {
operator = pmsOperatorService.findOperatorByLoginName(loginName);
session.setAttribute("PmsOperator", operator);
}
// 根据登录名查询角色
Long operatorId = operator.getId();
Set<String> roles = (Set<String>) session.getAttribute("ROLES");
if (roles == null || roles.isEmpty()) {
roles = pmsOperatorRoleService.getRoleCodeByOperatorId(operatorId);
session.setAttribute("ROLES", roles);
}
// 查询角色信息
authorizationInfo.setRoles(roles);
Set<String> permisstions = (Set<String>) session.getAttribute("PERMISSIONS");
if (permisstions == null || permisstions.isEmpty()) {
permisstions = pmsRolePermissionService.getPermissionsByOperatorId(operatorId);
session.setAttribute("PERMISSIONS", permisstions);
}
// 根据商户名查询权限
authorizationInfo.setStringPermissions(permisstions);
return authorizationInfo;
}
}
四、注册时加密方法工具类 PasswordHelper
/**
* 生成密码工具类
*/
public class PasswordHelper {
private static RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
private static String algorithmName = "md5";
private static String hashIteration = "2";
private static int hashIterations = Integer.valueOf(hashIteration);
public static void encryptPassword(PmsOperator pmsOperator) {
pmsOperator.setsalt(randomNumberGenerator.nextBytes().toHex());
String newPassword = new SimpleHash(algorithmName, pmsOperator.getLoginPwd(), ByteSource.Util.bytes(pmsOperator.getCredentialsSalt()), hashIterations).toHex();
pmsOperator.setLoginPwd(newPassword);
}
/**
* 加密密码
*
* @param loginPwd 明文密码
* @param salt
* @return
*/
public static String getPwd(String loginPwd, String salt) {
String newPassword = new SimpleHash(algorithmName, loginPwd, ByteSource.Util.bytes(salt), hashIterations).toHex();
return newPassword;
}
public static void main(String[] args) {
System.out.println(getPwd("********", "salt"));
}
}
五、数据库
1、pms_operator 用户表
2、pms_role_operator 用户角色关联表
3、pms_role 角色表
4、pms_role_permission 角色权限关联表
5、pms_permission 权限表
1、pms_operator 用户表
CREATE TABLE `pms_operator` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`version` bigint(20) NOT NULL,
`creater` varchar(50) NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`editor` varchar(50) DEFAULT NULL COMMENT '修改人',
`edit_time` datetime DEFAULT NULL COMMENT '修改时间',
`status` varchar(20) NOT NULL,
`remark` varchar(300) DEFAULT NULL,
`real_name` varchar(50) NOT NULL,
`mobile_no` varchar(50) NOT NULL,
`login_name` varchar(50) NOT NULL,
`login_pwd` varchar(256) NOT NULL,
`type` varchar(20) NOT NULL,
`salt` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
KEY `ak_key_2` (`login_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='操作员表';
2、pms_role 角色表
CREATE TABLE `pms_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`version` bigint(20) DEFAULT NULL,
`creater` varchar(50) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`editor` varchar(50) DEFAULT NULL COMMENT '修改人',
`edit_time` datetime DEFAULT NULL COMMENT '修改时间',
`status` varchar(20) DEFAULT NULL,
`remark` varchar(300) DEFAULT NULL,
`role_code` varchar(20) NOT NULL COMMENT '角色类型(1:超级管理员角色,0:普通操作员角色)',
`role_name` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `ak_key_2` (`role_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='角色表';
3、pms_role_operator 用户角色关联表
CREATE TABLE `pms_role_operator` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`version` bigint(20) NOT NULL,
`creater` varchar(50) NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`editor` varchar(50) DEFAULT NULL COMMENT '修改人',
`edit_time` datetime DEFAULT NULL COMMENT '修改时间',
`status` varchar(20) NOT NULL,
`remark` varchar(300) DEFAULT NULL,
`role_id` bigint(20) NOT NULL,
`operator_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `ak_key_2` (`role_id`,`operator_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='操作员与角色关联表';
4、pms_permission 权限表
CREATE TABLE `pms_permission` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`version` bigint(20) NOT NULL,
`creater` varchar(50) NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`editor` varchar(50) DEFAULT NULL COMMENT '修改人',
`edit_time` datetime DEFAULT NULL COMMENT '修改时间',
`status` varchar(20) NOT NULL,
`remark` varchar(300) DEFAULT NULL,
`permission_name` varchar(100) NOT NULL,
`permission` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `ak_key_2` (`permission`),
KEY `ak_key_3` (`permission_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='权限表';
5、pms_role_permission 角色权限关联表
CREATE TABLE `pms_role_permission` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`version` bigint(20) DEFAULT NULL,
`creater` varchar(50) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`editor` varchar(50) DEFAULT NULL COMMENT '修改人',
`edit_time` datetime DEFAULT NULL COMMENT '修改时间',
`status` varchar(20) DEFAULT NULL,
`remark` varchar(300) DEFAULT NULL,
`role_id` bigint(20) NOT NULL,
`permission_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `ak_key_2` (`role_id`,`permission_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1145 DEFAULT CHARSET=utf8 COMMENT='权限与角色关联表';
6、pms_menu 菜单表 用于显示系统左侧的菜单栏
CREATE TABLE `pms_menu` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`version` bigint(20) NOT NULL,
`creater` varchar(50) NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL COMMENT '创建时间',
`editor` varchar(50) DEFAULT NULL COMMENT '修改人',
`edit_time` datetime DEFAULT NULL COMMENT '修改时间',
`status` varchar(20) NOT NULL,
`remark` varchar(300) DEFAULT NULL,
`is_leaf` varchar(20) DEFAULT NULL,
`level` smallint(6) DEFAULT NULL,
`parent_id` bigint(20) NOT NULL,
`target_name` varchar(100) DEFAULT NULL,
`number` varchar(20) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
`url` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='菜单表';
7、pms_menu_role 菜单角色关联表
CREATE TABLE `pms_menu_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`version` bigint(20) DEFAULT NULL,
`creater` varchar(50) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`editor` varchar(50) DEFAULT NULL COMMENT '修改人',
`edit_time` datetime DEFAULT NULL COMMENT '修改时间',
`status` varchar(20) DEFAULT NULL,
`remark` varchar(300) DEFAULT NULL,
`role_id` bigint(20) NOT NULL,
`menu_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `ak_key_2` (`role_id`,`menu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1126 DEFAULT CHARSET=utf8 COMMENT='权限与角色关联表';
上一篇: 教你使用python获得字符串的md5值
下一篇: HTML怎么导出生成word文档?
推荐阅读