1.话不多说,直接引入ssm以及shiro整合依赖
<!--SSM整合--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.10.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.1.10.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--spring-mybatis整合--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency> <!--springmvc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.10.RELEASE</version> </dependency> <!--shiro的核心包--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency> <!--shiro整合spring--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version> </dependency> <!--单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!--sl4j与log4j2的适配--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.12.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>2.12.1</version> </dependency> </dependencies>
2.shiro-config.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--自定义realm交给spring ioc 容器管理--> <bean name="realm" class="com.wang.crm.shiro.ShiroRealm"/> <!--缓存管理器交给spring ioc 容器管理--> <bean name="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"/> <!--将安全管理器交给spring ioc 容器管理--> <bean name="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!--注入自定义realm--> <property name="realm" ref="realm"/> <!--注入缓存管理器--> <property name="cacheManager" ref="cacheManager"/> </bean> <!-- shiro 的Web过滤器 --> <bean name="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!--注入安全管理器--> <property name="securityManager" ref="securityManager"/> <!--如果没有认证将要跳转的登陆地址 --> <property name="loginUrl" value="/login"/> <!-- 配置安全规则 --> <property name="filterChainDefinitions"> <value> <!-- 登录页面不拦截 --> /login anon <!--静态资源可以直接访问--> /static/** anon /upload/** anon <!-- user表示身份认证通过可以访问 --> /** user </value> </property> </bean> <!-- 使用SecurityUtils将securityManager设置到运行环境中 SecurityUtils.setSecurityManager(securityManager); --> <!-- 相当于调用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> <!-- Shiro生命周期处理器--> <bean name="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
3.spring-config.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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--启用注解扫描,扫描含有注解的类--> <context:component-scan base-package="com.wang.*.service"/> <!--加载属性配置文件--> <context:property-placeholder location="classpath:application.properties"/> <!--将数据源交给Spring IOC 容器来管理--> <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="url" value="${jdbc.url}"/> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="initialSize" value="${jdbc.initialSize}"/> </bean> <!--配置Mapper接口的扫描器--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--配置mapper接口所在的包--> <property name="basePackage" value="com.wang.crm.mapper"/> <!--注入会话工厂--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean> <!--SqlSessionFactory 会话工厂交给spring容器管理--> <bean name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--注入数据源--> <property name="dataSource" ref="dataSource"/> <!--配置Mapper映射文件的位置--> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!--配置jdbc的事务管理器--> <bean name="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源--> <property name="dataSource" ref="dataSource"/> </bean> <!-- aop注解生效 --> <aop:aspectj-autoproxy/> <!--启用事务注解支持--> <tx:annotation-driven transaction-manager="txManager"/> <!--引入shiro的核心配置--> <import resource="classpath:shiro-config.xml"/> </beans>
4.springmvc-config.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:context="http://www.springframework.org/schema/context" 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--开启注解扫描--> <context:component-scan base-package="com.wang.*.controller"/> <!-- 启用springmvc注解开发功能--> <mvc:annotation-driven/> <!--不拦截静态资源--> <mvc:default-servlet-handler/> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <!--文件上传解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 限制文件上传总大小,不设置默认没有限制,单位为字节 200*1024*1024即200M --> <property name="maxUploadSize" value="209715200"/> <!-- 设置每个上传文件的大小上限 1024*1024*2 2M --> <property name="maxUploadSizePerFile" value="2019152"/> <!-- 处理文件名中文乱码 --> <property name="defaultEncoding" value="UTF-8"/> <!-- resolveLazily属性启用是为了推迟文件解析,以便捕获文件大小异常 --> <property name="resolveLazily" value="true"/> </bean> <!--配置拦截器--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/login"/> <mvc:exclude-mapping path="/static/**"/> <mvc:exclude-mapping path="/upload/**"/> <bean class="com.wang.crm.interceptor.AuthHandlerInterceptor"/> </mvc:interceptor> </mvc:interceptors> <!-- 开启aop对类代理 --> <aop:config proxy-target-class="true"/> <!-- 开启shiro注解支持 配置shiro的注解适配器--> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> </beans>
5.application.properties
jdbc.username=root jdbc.password=123456 jdbc.url=jdbc:mysql://127.0.0.1:3306/shiro_crm?useSSL=false&serverTimezone=Asia/Shanghai jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.initialSize=5
6.ShiroUtil.java
package com.wang.crm.utils; import com.wang.crm.shiro.ShiroRealm; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.cache.MemoryConstrainedCacheManager; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.realm.Realm; import org.apache.shiro.realm.text.IniRealm; import org.apache.shiro.subject.Subject; /** * @author 王一宁 * @date 2020/3/15 12:52 */ public class ShiroUtil { /** * 初始化shiro的环境 */ static{ //1.初始化Shiro的安全管理器 DefaultSecurityManager securityManager = new DefaultSecurityManager(); //2.设置用户的权限信息到安全管理器 //Realm realm = new IniRealm("classpath:shiro.ini"); //2.使用自己定义二relam 操作数据库 查看权限,不看ini了 Realm realm = new ShiroRealm(); securityManager.setRealm(realm); //3.配置缓存管理器 CacheManager cacheManager = new MemoryConstrainedCacheManager(); securityManager.setCacheManager(cacheManager); //4.设置到运行环境中 SecurityUtils.setSecurityManager(securityManager); } /** * 登录认证授权 * @param username * @param password */ public static Subject login(String username,String password){ //1.创建一个subject实例 Subject subject = SecurityUtils.getSubject(); //2.创建一个用户的账号密码Token AuthenticationToken token = new UsernamePasswordToken(username,password); //3.登录 subject.login(token); return subject; } }
7.ShiroRealm.java
package com.wang.crm.shiro; import com.wang.crm.mapper.UserMapper; import com.wang.crm.model.User; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import javax.xml.ws.Action; import java.text.SimpleDateFormat; import java.util.HashSet; import java.util.Set; /** * @author 王一宁 * @date 2020/3/15 13:12 */ public class ShiroRealm extends AuthorizingRealm { @Autowired UserMapper userMapper; /** * 登录认证 */ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("开始进行用户登录认证..."); UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; //1.获取用户名 密码 String username = token.getUsername(); String password = new String(token.getPassword()); //2.根据用户名密码,去数据库Mysql 查询用户信息 User user = userMapper.selectByUserNameAndPassword(username); //3.对比结果 if (!user.getUsername().equals(username)){ throw new UnknownAccountException("用户名不存在!"); } if (!user.getPassword().equals(password)){ throw new CredentialsException(("密码错误!")); } if (user.getStatus() == 1){ throw new DisabledAccountException("账号被禁用了!"); } if (user.getStatus() == 2){ throw new LockedAccountException("账号被锁定了!"); } System.out.println("认证成功..."); //4.创建简单信息认证对象,相当与设置到了Session会话中 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,token.getCredentials(),getName()); return info; } /** * 授权资源 * 将认证通过的用户的角色和权限设置到用户上 */ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("开始进行授权..."); //1.简单授权信息对象,包含了角色和权限信息 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //2.从数据库中获取角色 User user = (User) principalCollection.getPrimaryPrincipal(); Set<String> roleNameSet = userMapper.selectUserRoleNameSet(user.getUserId()); //添加角色和权限列表 info.addRoles(roleNameSet); //3.查询权限 Set<String> permissionNameSet = userMapper.selectUserPermissionNameSet(user.getUserId()); //因为一个用户有很多权限,拼接的 ,需要拆分放入shiro Set<String> permissions = new HashSet<>(); for (String name:permissionNameSet){ for (String permission : name.split(",")){ permissions.add(permission); } } //添加角色和权限列表 info.addStringPermissions(permissions); System.out.println("授权完成。。。"); return info; } }