SSM集成Shiro安全框架(一)

本文详细介绍了Apache Shiro框架在Java应用中实现权限管理和身份验证的过程。从Maven依赖引入到Spring配置,再到自定义Realm的实现,以及JSP标签的使用,全面展示了Shiro在实际项目中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、目录结构

二、基础配置文件

1.pom.xml

		<!-- 引入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-web</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-ehcache</artifactId>
			<version>1.2.3</version>
		</dependency>

		<dependency>
			<artifactId>ehcache-core</artifactId>
			<groupId>net.sf.ehcache</groupId>
			<version>2.5.0</version>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-quartz</artifactId>
			<version>1.2.3</version>
		</dependency>

		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.2.2</version>
		</dependency>

		<!-- Shiro 集成验证码 -->
		<dependency>
			<groupId>com.github.penggle</groupId>
			<artifactId>kaptcha</artifactId>
			<version>2.3.2</version>
		</dependency>

2.web.xml

	<!-- 配置 Shiro 的 Filter -->
	<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>

		<dispatcher>REQUEST</dispatcher>
		<dispatcher>FORWARD</dispatcher>
		<dispatcher>ERROR</dispatcher>
		<dispatcher>INCLUDE</dispatcher>
	</filter-mapping>

3.shiro.sql

/*
Navicat MySQL Data Transfer

Source Server         : localhost_3306
Source Server Version : 50537
Source Host           : localhost:3306
Source Database       : shiro

Target Server Type    : MYSQL
Target Server Version : 50537
File Encoding         : 65001

Date: 2018-09-03 10:12:43
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `permission`
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
  `id` bigint(8) NOT NULL AUTO_INCREMENT,
  `name` varchar(16) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES ('1', 'addProduct');
INSERT INTO `permission` VALUES ('2', 'deleteProduct');
INSERT INTO `permission` VALUES ('3', 'editeProduct');
INSERT INTO `permission` VALUES ('4', 'updateProduct');
INSERT INTO `permission` VALUES ('5', 'listProduct');
INSERT INTO `permission` VALUES ('6', 'addOrder');
INSERT INTO `permission` VALUES ('7', 'deleteOrder');
INSERT INTO `permission` VALUES ('8', 'editeOrder');
INSERT INTO `permission` VALUES ('9', 'updateOrder');
INSERT INTO `permission` VALUES ('10', 'listOrder');

-- ----------------------------
-- Table structure for `role`
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `id` bigint(8) NOT NULL AUTO_INCREMENT,
  `name` varchar(16) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES ('1', 'admin');
INSERT INTO `role` VALUES ('2', 'productManager');
INSERT INTO `role` VALUES ('3', 'orderManager');

-- ----------------------------
-- Table structure for `role_permission`
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
  `rid` bigint(20) NOT NULL DEFAULT '0',
  `pid` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`rid`,`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of role_permission
-- ----------------------------
INSERT INTO `role_permission` VALUES ('1', '1');
INSERT INTO `role_permission` VALUES ('1', '2');
INSERT INTO `role_permission` VALUES ('1', '3');
INSERT INTO `role_permission` VALUES ('1', '4');
INSERT INTO `role_permission` VALUES ('1', '5');
INSERT INTO `role_permission` VALUES ('1', '6');
INSERT INTO `role_permission` VALUES ('1', '7');
INSERT INTO `role_permission` VALUES ('1', '8');
INSERT INTO `role_permission` VALUES ('1', '9');
INSERT INTO `role_permission` VALUES ('1', '10');
INSERT INTO `role_permission` VALUES ('2', '1');
INSERT INTO `role_permission` VALUES ('2', '2');
INSERT INTO `role_permission` VALUES ('2', '3');
INSERT INTO `role_permission` VALUES ('2', '4');
INSERT INTO `role_permission` VALUES ('2', '5');
INSERT INTO `role_permission` VALUES ('3', '6');
INSERT INTO `role_permission` VALUES ('3', '7');
INSERT INTO `role_permission` VALUES ('3', '8');
INSERT INTO `role_permission` VALUES ('3', '9');
INSERT INTO `role_permission` VALUES ('3', '10');

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint(8) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `password` varchar(32) DEFAULT NULL,
  `salt` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'admin', '68609b8b64988c0f4def093eaa025e05', 'abcd');
INSERT INTO `user` VALUES ('2', 'li4', 'abcde', 'abcd');

-- ----------------------------
-- Table structure for `user_role`
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
  `uid` bigint(20) NOT NULL DEFAULT '0',
  `rid` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`uid`,`rid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES ('1', '1');
INSERT INTO `user_role` VALUES ('1', '2');
INSERT INTO `user_role` VALUES ('2', '2');

三、权限控制demo

1.Spring配置文件(applicationContext.xml)中导入shiro配置文件:

	<!-- 引入shiro的配置文件 -->
	<import resource="classpath:applicationContext-shiro.xml" /> <!-- 7 -->

2.shiro配置文件applicationContext-shiro.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.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 http://www.springframework.org/schema/mvc
	http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/util 
	http://www.springframework.org/schema/util/spring-util.xsd">

	<!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
	<bean id="shiroFilter"
		class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 调用我们配置的权限管理器 -->
		<property name="securityManager" ref="securityManager" />
		<!-- 配置我们的登录请求地址 -->
		<property name="loginUrl" value="/login.jsp" />
		<!-- 配置我们在登录页登录成功后的跳转地址,如果你访问的是非/login地址,则跳到您访问的地址  -->
		<property name="successUrl" value="/index.jsp" />
		<!-- 如果您请求的资源不再您的权限范围,则跳转到/403请求地址 -->
		<property name="unauthorizedUrl" value="/unauthorized.jsp" />
		<property name="filters">
			<util:map>
				<entry key="logout" value-ref="logoutFilter" />
			</util:map>
		</property>
		<!-- 权限配置 -->
		<property name="filterChainDefinitions">
			<value>
				<!-- anon表示此地址不需要任何权限即可访问 -->
				/login=anon
				/kaptcha=anon
				/kaptcha/get=anon
				/icon/**=anon
				/js/**=anon
				/css/**=anon
				<!--  -->/index.jsp = roles[admin]
				<!--/index.jsp = roles["admin","productManager"] 要同时具有admin,productManager两个角色权限 -->
				<!--/index.jsp = roleOrFilter["admin","productManager"] 只需具有其中一个权限就可以,但需要自定义filter -->
				/logout=logout
				<!-- 所有的请求(除去配置的静态资源请求或请求地址为anon的请求)都要通过登录验证,如果未登录则跳到/login -->
				/** = authc

			</value>
		</property>
	</bean>
	
	<!-- 退出登陆配置 -->
	<bean id="logoutFilter"
		class="org.apache.shiro.web.filter.authc.LogoutFilter">
		<!-- 重定向退出登陆的地址 -->
		<property name="redirectUrl" value="logout.jsp" />
	</bean>

	<!-- 会话ID生成器 -->
	<bean id="sessionIdGenerator"
		class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" />
	<!-- 会话Cookie模板 关闭浏览器立即失效 -->
	<bean id="sessionIdCookie"
		class="org.apache.shiro.web.servlet.SimpleCookie">
		<constructor-arg value="sid" />
		<property name="httpOnly" value="true" />
		<property name="maxAge" value="-1" />
	</bean>
	<!-- 会话DAO -->
	<bean id="sessionDAO"
		class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
		<property name="sessionIdGenerator" ref="sessionIdGenerator" />
	</bean>
	<!-- 会话验证调度器,每30分钟执行一次验证 ,设定会话超时及保存 -->
	<bean name="sessionValidationScheduler"
		class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler">
		<property name="interval" value="1800000" />
		<property name="sessionManager" ref="sessionManager" />
	</bean>
	<!-- 会话管理器 -->
	<bean id="sessionManager"
		class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<!-- 全局会话超时时间(单位毫秒),默认30分钟 -->
		<property name="globalSessionTimeout" value="1800000" />
		<property name="deleteInvalidSessions" value="true" />
		<property name="sessionValidationSchedulerEnabled" value="true" />
		<property name="sessionValidationScheduler" ref="sessionValidationScheduler" />
		<property name="sessionDAO" ref="sessionDAO" />
		<property name="sessionIdCookieEnabled" value="true" />
		<property name="sessionIdCookie" ref="sessionIdCookie" />
	</bean>

	<!-- 安全管理器 -->
	<bean id="securityManager"
		class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="userRealm" /> <!-- 1 -->
		<!-- 使用下面配置的缓存管理器 -->
		<property name="cacheManager" ref="cacheManager" />
		<property name="sessionManager" ref="sessionManager" />
	</bean>
	<!-- 相当于调用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>

	<!-- 注册自定义的Realm,并把密码匹配器注入,使用注解的方式自动注解会无法正确匹配密码 -->
	<bean id="userRealm" class="com.yan.shiro.common.UserRealm"><!-- 2 -->
		<!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 -->
		<property name="credentialsMatcher" ref="credentialsMatcher" />
	</bean>

	<bean id="credentialsMatcher"
		class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
		<property name="hashAlgorithmName" value="MD5"></property> <!-- 加密算法的名称 -->
		<property name="hashIterations" value="1024"></property> <!-- 配置加密的次数 -->
	</bean>
	<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> </bean>

	<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

	<bean
		class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<property name="exceptionMappings">
			<props>
				<prop key="org.apache.shiro.authz.UnauthorizedException">/403</prop>
			</props>
		</property>
	</bean>
</beans> 

3.定义shiro拦截器(UserRealm.java)

package com.yan.shiro.common;

import java.util.Set;


import org.apache.shiro.SecurityUtils;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import com.yan.shiro.model.User;
import com.yan.shiro.service.UserService;

public class UserRealm extends AuthorizingRealm {

	@Autowired
	private UserService userService;

	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println("UserRealm的doGetAuthorizationInfo方法开始执行");
		//获取当前登陆的用户名
		String username=(String)principals.getPrimaryPrincipal();
		System.out.println("username:"+username);
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		//从数据库中查找该用户名拥有的角色
		Set<String> roleList = userService.selectRoleByUserName(username);
		// 添加角色
		authorizationInfo.addRoles(roleList);
		// 添加权限
		// authorizationInfo.setStringPermissions(userService.findPermissions(username));
		return authorizationInfo;
	}
	
	/**
	 * 登陆验证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		System.out.println("UserRealm的doGetAuthenticationInfo方法开始执行");
		//获取当前登陆的用户名
		String userName = (String) token.getPrincipal();
		//从数据库中获取user
		User user = userService.selectByUserName(userName);
		// 为密码加盐
		ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());// 这里的参数要给个唯一的;
		// 校验
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getName(), user.getPassword(),credentialsSalt, getName());
		return authenticationInfo;
	}
	
	public static void main(String[] args) {
		SimpleHash MD5 = new SimpleHash("MD5", "123456", ByteSource.Util.bytes("小明"), 1024);
		System.out.println(MD5);
	}
}

4.UserController.java

	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String login(HttpServletRequest request) {
		System.out.println("UserController的login方法开始执行");
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		Subject subject = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken(username,password);
		try {
			//执行认证操作.
			subject.login(token);
		} catch (Exception e) {
			e.printStackTrace();
			return "error";
		}
		return "success";
	}

四、JSP标签

1.导入标签库

<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

2.guest标签

<shiro:guest>
欢迎游客访问,<a href="${pageContext.request.contextPath}/login.jsp">登录</a>
</shiro:guest>

3.user 标签

<shiro:user>
欢迎 用户访问,<a href="${pageContext.request.contextPath}/login.jsp">登录</a>
</shiro:user>

4.principal 标签

<!-- 显示用户身份信息,默认调用 Subject.getPrincipal() 获取-->
<shiro:principal type="java.lang.String"/><!-- 相当于 Subject.getPrincipals().oneByType(String.class)  -->

<shiro:principal type="java.lang.String"/> <!-- 相当于 Subject.getPrincipals().oneByType(String.class) -->

5.lacksRole 标签

<shiro:lacksRole name="abc">
    用户[<shiro:principal/>]没有角色abc<br/> <!-- 如果当前 Subject abc角色将显示 body 体内容。 -->
</shiro:lacksRole>

6.hasPermission 标签

<shiro:hasPermission name="user:create">
    用户[<shiro:principal/>]拥有权限user:create<br/> <!-- 如果当前 Subject 有create权限将显示 body 体内容。 -->
</shiro:hasPermission>

7.lacksPermission 标签

<shiro:lacksPermission name="org:create">
    用户[<shiro:principal/>]没有权限org:create<br/> <!-- 如果当前 Subject 没有create权限将显示 body 体内容。  -->
</shiro:lacksPermission>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值