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 versinotallow="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 versinotallow="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 versinotallow="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;
}
}