1.完成ssm整合shiro
企业中老项目还在使用ssm框架。
准备数据库
数据结构
张三 -user:query user:add user:update user:delete
李四 ---》user:query user:add user:update
王五-----》user:query user:export
搭建ssm的环境
(1)创建一个maven的web工程。
(2)ssm整合到web工程
1.pom依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>ssm-shiro1029</artifactId> <version>1.0-SNAPSHOT</version> <!--版本和依赖分离--> <properties> <spring.version>5.2.15.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.9.0</version> </dependency> <!--spring-webmvc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!--mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <!--mybatis和spring整合的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> <!--druid连接池依赖--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.1</version> </dependency> <!--lombok依赖--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency> <!--jackson java对象转换为json对象 @ResponseBody--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.2.2</version> </dependency> <!--servlet-api依赖--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.15.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.15.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.15.RELEASE</version> </dependency> <!--generator--> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.3.0</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> </project>
2.spring配置文件(spring和springmvc配置在一起)
<?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:mvc="http://www.springframework.org/schema/mvc" 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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 包扫描 --> <context:component-scan base-package="com.wzh"/> <!-- 开启注解 --> <mvc:annotation-driven /> <!-- 静态资源放行 --> <mvc:default-servlet-handler/> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <!-- 启动Shrio的注解 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.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> <!-- 德鲁伊连接池 --> <bean id="dataResource" class="com.alibaba.druid.pool.DruidDataSource"> <!--驱动名称--> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/shiro?serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="123456"/> <!--初始化连接池的个数--> <property name="initialSize" value="10"/> <!--至少的个数--> <property name="minIdle" value="5"/> <!--最多的个数--> <property name="maxActive" value="10"/> <!--最长等待时间单位毫秒--> <property name="maxWait" value="2000"/> </bean> <!--创建事务管理类--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataResource"/> </bean> <!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- sqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataResource"/> <!-- 配置映射文件 --> <property name="mapperLocations" value="classpath:mapper/*.xml"/> <!-- 配置分页 --> <property name="plugins" > <array> <bean class="com.github.pagehelper.PageInterceptor"/> </array> </property> </bean> <!--dao接口的代理实现类--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.wzh.mapper"/> </bean> <!--下面是shiro中需要加的--> <!--整合shiro的配置内容--> <!--1、配置securityManager--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="realm"/> </bean> <!--2、配置自定义的Realm--> <bean id="realm" class="com.wzh.realm.MyRealm"> <property name="credentialsMatcher" ref="credentialsMatcher"/> </bean> <!--3、创建密码匹配器--> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="MD5"/> <property name="hashIterations" value="1024"/> </bean> <!--shiro过滤工厂: 设置过滤的规则--> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- Shiro的核心安全接口,这个属性是必须的 --> <property name="securityManager" ref="securityManager"/> <!--设置未登录的跳转路径--> <!-- <property name="loginUrl" value="/login.jsp"/>--> <!--设置没有权限的跳转路径--> <!-- <property name="unauthorizedUrl" value="/unauthorizedUrl.jsp"/>--> <!--设置过滤器--> <property name="filterChainDefinitions"> <value> /login=anon /**=authc </value> </property> <!--未登录 过滤器--> <property name="filters"> <map> <entry key="authc"> <!--自定义过滤器所在的路径--> <bean class="com.wzh.filter.LoginFilter"/> </entry> </map> </property> </bean> </beans>
3.web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--shiro过滤器的代理--> <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> <!-- 注册servlet --> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 解决中文乱码 注册文字格式拦截器 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
上面是spring和springmvc配置文件在一起的,有的时候spring配置文件和springmvc文件没有在一起,如下
application.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:mvc="http://www.springframework.org/schema/mvc" 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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 包扫描 --> <context:component-scan base-package="com.wzh.service"/> <!--导入db.properties--> <!--引入属性文件--> <context:property-placeholder location="classpath:db.properties"/> <!--配置数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!--SqlSessionFactoryBean--> <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!--为Dao生成实现类--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.wzh.dao"/> </bean> <!--事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
springmvc.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" 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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 包扫描 --> <context:component-scan base-package="com.wzh.controller"/> <!--静态资源放行--> <mvc:default-servlet-handler/> <!--注解驱动--> <mvc:annotation-driven/> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--监听器 加载spring配置文件--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 前端控制器 加载springmvc配置文件--> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 解决中文乱码 注册文字格式拦截器 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
4.mapper.xml配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wzh.mapper.PermissionMapper"> </mapper>
controller service dao entity文件夹创建 省略,
5.登录页面和成功页面准备好
整合shiro
(1)引入shiro的依赖
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.9.0</version>
</dependency>
(2)spring的配置文件添加shiro的配置
<?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:mvc="http://www.springframework.org/schema/mvc"
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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 包扫描 -->
<context:component-scan base-package="com.wzh.service"/>
<!--导入db.properties-->
<!--引入属性文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--SqlSessionFactoryBean-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!--为Dao生成实现类-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.wzh.dao"/>
</bean>
<!--事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--spring整合shiro-->
<!--SecurityManager的管理-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"/>
</bean>
<!--创建Realm对象-->
<bean id="myRealm" class="com.wzh.realm.MyRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
<!--创建密码加密器-->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"/>
<property name="hashIterations" value="1024"/>
</bean>
<!--设置shiro的过滤器链
id:后面要求必须和web.xml中的配置名称相同
-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--设置安全管理对象-->
<property name="securityManager" ref="securityManager"/>
<!--如果没有认证 则跳转到登录页面-->
<property name="loginUrl" value="/toLogin"/>
<!--如果没有权限,跳转的路径-->
<property name="unauthorizedUrl" value="/unauthorizedUrl.jsp"/>
<!--过滤器链-->
<!--anon:表示允许匿名访问
authc:需要认证后才可以访问
-->
<property name="filterChainDefinitions">
<value>
/index.jsp=anon
/login=anon
/**=authc
</value>
</property>
</bean>
</beans>
如果jsp文件都在webapp下,并没有在WEB-INF下的views中设置如下:
<!--整合shiro的配置内容-->
<!--①SecurityManager-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="realm"/>
</bean>
<!--创建自定义realm类对象-->
<bean id="realm" class="com.ykq.realm.MyRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
<!--创建密码匹配器-->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"/>
<property name="hashIterations" value="1024"/>
</bean>
<!--shiro过滤工厂: 设置过滤的规则-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--如果没有登录,跳转的路径-->
<property name="loginUrl" value="/login.jsp"/>
<!--没有权限,跳转的路径-->
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<property name="filterChainDefinitions">
<value>
/login=anon
/**=authc
</value>
</property>
</bean>
shiro中内置很多过滤器,而每个过滤都有相应的别名.
(3) 修改web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--shiro过滤器-->
<filter>
<!--该名称必须和ShiroFilterFactoryBean的id相同(也就是spring配置文件中的ShiroFilterFactoryBean)-->
<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>
<!--监听器 加载spring配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 前端控制器 加载springmvc配置文件-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 解决中文乱码 注册文字格式拦截器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
(4)controller
package com.wzh.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @ProjectName: ssm-shiro-1029
* @Package: com.wzh.controller
* @ClassName: PageController
* @Author: 王振华
* @Description:
* @Date: 2022/10/29 19:07
* @Version: 1.0
*/
@Controller
public class PageController {
@GetMapping("/toLogin")
public String toLogin(){
return "login";//经过视图解析器,找到WEB-INF/views下
}
@ResponseBody
@RequestMapping("login")
public String login(String username, String password) {
System.out.println(username);
//获取subject主体对象
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
return "success";
} catch (Exception e) {
e.printStackTrace();
return "fail";
}
}
}
(5) myRealm
package com.wzh.realm;
import com.wzh.pojo.entity.User;
import com.wzh.service.UserService;
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import java.util.List;
/**
* @ProjectName: maven-shiro1028
* @Package: com.wzh.realm
* @ClassName: MyRealm
* @Author: 王振华
* @Description:
* @Date: 2022/10/28 19:07
* @Version: 1.0
*/
public class MyRealm extends AuthorizingRealm {
private UserService userService = new UserService();
//授权时执行该方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//认证时执行该方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("认证方法=====");
//1.获取登录者的账号
String username = authenticationToken.getPrincipal().toString();
//2.根据账号查询数据库
User user = userService.findByUsername(username);
if(user!=null){
//Object principal,账号数据库中
// Object credentials,密码数据库中
//ByteSource credentialsSalt 使用的盐
// String realmName realm的名称随便起
//密码的比对交于SimpleAuthenticationInfo
//未来在数据中一列设置为存放盐
ByteSource salt = ByteSource.Util.bytes(user.getSalt());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getUserpwd(),salt,this.getName());
return info;
}
return null;
}
}
(6)service
package com.wzh.service;
import com.wzh.dao.UserMapper;
import com.wzh.pojo.entity.User;
import com.wzh.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.service.impl
* @ClassName: UserServiceImpl
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:20
* @Version: 1.0
*/
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User findByUsername(String username) {
if(username!=null&&username!="") {
User user = userMapper.selectByUsername(username);
return user;
}
return null;
}
}
(7)userMapper.xml,dao层省略
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wzh.dao.UserMapper">
<select id="selectByUsername" resultType="com.wzh.pojo.entity.User">
select * from user where username = #{username}
</select>
</mapper>
1.1. 进入主页后,不同的用户可以看到不同的内容。
<%--
Created by IntelliJ IDEA.
User: m1762
Date: 2022/8/4
Time: 22:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<shiro:hasPermission name="user:query">
<a href="/query">查询用户</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:add">
<a href="/add">添加用户</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:delete">
<a href="/delete">删除用户</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:update">
<a href="/update">修改用户</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:export">
<a href="/export">导出用户</a>
</shiro:hasPermission>
</body>
</html>
可以在jsp中获取当前登录者的账号
<h1>欢迎<shiro:principal property="username"/>来到主页</h1>
上面只是在网页中根据不同用户显示不同的菜单,这种方式只能防君子不能防小人。因为现在依旧可以通过postman访问没有的权限方法 比如张三可以访问到user:export路径
解决办法:
拦截器---获取请求路径 然后根据你的路径判断当前用户是否具有该权限。
spring整合shiro时提供了一个注解:可以加载相应方法上。
使用注解:
1.springmvc.xml中启动shiro的注解
<!-- 启动Shrio的注解 -->
<bean id="lifecycleBeanPostProcessor"
class="org.apache.shiro.spring.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>
(2)使用注解
这个太丑了,我们想要跳转一个页面,
我们之前学过全局异常处理: 没有登录会报这个异常
2.ssm整合shiro完成前后端分离
所谓前后端完全分离:后端响应的都是json数据,而不再是网页。
我们需要修改的就是:
1. 登录成功或者失败应该返回json数据
2. 当未登录时返回的也是json数据
3. 访问未授权的资源,也要分会json。
2.1.登录成功或者失败应该返回json数据
修改登录接口
2.2 当未登录时返回的也是json数据
(1)创建一个过滤器,继承登录校验的FormAuthenticationFilter接口。
package com.wzh.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wzh.utils.CommonResult;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.PrintWriter;
/**
* @ProjectName: shiro-ssm0805
* @Package: com.wzh.filter
* @ClassName: LoginFilter
* @Author: 王振华
* @Description:
* @Date: 2022/8/5 16:58
* @Version: 1.0
*/
public class LoginFilter extends FormAuthenticationFilter {
/**
* 当没有登录时会经过该方法,如果想让它返回json数据必须重写onAccessDenied这个方法
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
CommonResult commonResult = CommonResult.UNLOGIN;
//jackson中内置对象 将java对象转为json对象
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(commonResult);
//响应给客户json数据
writer.print(json);
writer.flush();
writer.close();
return false;
}
}
之前默认是在springmvc.xml中配置的跳转页面
(2) 注册我们的过滤器
2.3 如果没有权限应该返回json数据
3.项目完整代码
项目结构:
Controller层:
UserController: 用于登录 调用login方法判断是否身份认证 授权
package com.wzh.controller;
import com.wzh.utils.CommonResult;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.controller
* @ClassName: UserController
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:07
* @Version: 1.0
*/
@RestController
public class UserController {
@RequestMapping("login")
public CommonResult login(String username,String password){
System.out.println(username);
//获取subject主体对象
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try{
subject.login(token);
System.out.println("是否身份认证:"+subject.isAuthenticated());
System.out.println("是否授权:"+subject.isPermitted("查询"));
System.out.println("是否授权:"+subject.isPermitted("添加"));
System.out.println("是否授权:"+subject.isPermitted("修改"));
System.out.println("是否授权:"+subject.isPermitted("删除"));
System.out.println("是否授权:"+subject.isPermitted("导出"));
System.out.println("是否授权:"+subject.hasRole("超级管理员"));
System.out.println("是否授权:"+subject.hasRole("管理员"));
System.out.println("是否授权:"+subject.hasRole("用户"));
return CommonResult.LOGIN_SUCCESS;
}catch (Exception e){
e.printStackTrace();
return CommonResult.LOGIN_ERROR;
}
}
}
PermissionController: 用于登录之后查看是否授权
package com.wzh.controller;
import com.wzh.utils.CommonResult;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @ProjectName: shiro-ssm0805
* @Package: com.wzh.controller
* @ClassName: PermissionController
* @Author: 王振华
* @Description:
* @Date: 2022/8/5 9:57
* @Version: 1.0
*/
@RestController
public class PermissionController {
@GetMapping("/query")
//使用shiro注解
@RequiresPermissions(value = {"user:query","user:aaa"},logical = Logical.OR)
public String query(){
return "query";
}
@RequestMapping("/add")
@RequiresPermissions(value = {"user:add"})
public String add(){
return "add";
}
@RequestMapping("/delete")
@RequiresPermissions(value = {"user:delete"})
public String delete(){
return "delete";
}
@RequestMapping("/update")
@RequiresPermissions(value = {"user:update"})
public String update(){
return "update";
}
@RequestMapping("/export")
@RequiresPermissions(value = {"user:export"})
public String export(){
return "export";
}
}
service层:
UserService:
package com.wzh.service;
import com.wzh.entity.User;
import java.util.List;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.service
* @ClassName: UserService
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:19
* @Version: 1.0
*/
public interface UserService {
User findByUsername(String username);
}
PermissionService:
package com.wzh.service;
import java.util.List;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.service
* @ClassName: PermissionService
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:27
* @Version: 1.0
*/
public interface PermissionService {
List<String> findPermissionById(Integer userid);
}
RoleService:
package com.wzh.service;
import java.util.List;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.service
* @ClassName: RoleService
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:27
* @Version: 1.0
*/
public interface RoleService {
List<String> findRolesById(Integer userid);
}
UserServiceImpl:
package com.wzh.service.impl;
import com.wzh.entity.User;
import com.wzh.mapper.UserMapper;
import com.wzh.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.service.impl
* @ClassName: UserServiceImpl
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:20
* @Version: 1.0
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByUsername(String username) {
if(username!=null&&username!="") {
User user = userMapper.selectByUsername(username);
return user;
}
return null;
}
}
PermissionServiceImpl:
package com.wzh.service.impl;
import com.wzh.mapper.PermissionMapper;
import com.wzh.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.service.impl
* @ClassName: PermissionServiceImpl
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:28
* @Version: 1.0
*/
@Service
public class PermissionServiceImpl implements PermissionService {
@Autowired
private PermissionMapper permissionMapper;
@Override
public List<String> findPermissionById(Integer userid) {
List<String> list = permissionMapper.selectByUserId(userid);
return list;
}
}
RoleServiceImpl:
package com.wzh.service.impl;
import com.wzh.mapper.RoleMapper;
import com.wzh.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.service.impl
* @ClassName: RoleServiceImpl
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:28
* @Version: 1.0
*/
@Service
public class RoleServiceImpl implements RoleService {
@Autowired
private RoleMapper roleMapper;
@Override
public List<String> findRolesById(Integer userid) {
List<String> list = roleMapper.selectByUserId(userid);
return list;
}
}
mapper层:
UserMapper:
package com.wzh.mapper;
import com.wzh.entity.User;
import java.util.List;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.mapper
* @ClassName: UserMapper
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:21
* @Version: 1.0
*/
public interface UserMapper {
User selectByUsername(String username);
}
PermissionMapper:
package com.wzh.mapper;
import java.util.List;
/**
@ProjectName: ssm-shiro
@Package: com.wzh.mapper
@ClassName: PermissionMapper
@Author: 王振华
@Description:
@Date: 2022/8/4 22:21
@Version: 1.0
*/
public interface PermissionMapper {
List<String> selectByUserId(Integer userid);
}
RoleMapper:
package com.wzh.mapper;
import java.util.List;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.mapper
* @ClassName: RoleMapper
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:21
* @Version: 1.0
*/
public interface RoleMapper {
List<String> selectByUserId(Integer userid);
}
entity层:
User:
package com.wzh.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.management.relation.Role;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.entity
* @ClassName: User
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:19
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer userid;
private String username;
private String userpwd;
private String sex;
private String address;
private String salt;
private Permission permission;
private Role role;
}
Permission:
package com.wzh.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.entity
* @ClassName: Permission
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:22
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Permission {
private Integer perid;
private String pername;
private String percode;
}
Role:
package com.wzh.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ProjectName: ssm-shiro
* @Package: com.wzh.entity
* @ClassName: Role
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 22:22
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
private Integer roleid;
private String rolename;
}
filter:
LoginFilter: 用于未登录返回json数据
package com.wzh.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wzh.utils.CommonResult;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.PrintWriter;
/**
* @ProjectName: shiro-ssm0805
* @Package: com.wzh.filter
* @ClassName: LoginFilter
* @Author: 王振华
* @Description:
* @Date: 2022/8/5 16:58
* @Version: 1.0
*/
public class LoginFilter extends FormAuthenticationFilter {
/**
* 当没有登录时会经过该方法,如果想让它返回json数据必须重写onAccessDenied这个方法
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
CommonResult commonResult = CommonResult.UNLOGIN;
//jackson中内置对象 将java对象转为json对象
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(commonResult);
//响应给客户json数据
writer.print(json);
writer.flush();
writer.close();
return false;
}
}
handler: 全局异常处理类 用户没有权限返回json数据给前端
MyException:
package com.wzh.handler;
import com.wzh.utils.CommonResult;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @ProjectName: shiro-ssm0805
* @Package: com.wzh.handler
* @ClassName: MyException
* @Author: 王振华
* @Description:
* @Date: 2022/8/5 16:42
* @Version: 1.0
*/
@ControllerAdvice //异常处理类
public class MyException {
//当发生该异常时触发该方法
@ExceptionHandler(value = UnauthorizedException.class)
@ResponseBody
public CommonResult Unauth(UnauthorizedException e){
e.printStackTrace();
return CommonResult.UNAUTHORIZED;
}
}
realm: 自定义的认证授权规则
MyRealm:
package com.wzh.realm;
import com.wzh.entity.User;
import com.wzh.service.PermissionService;
import com.wzh.service.RoleService;
import com.wzh.service.UserService;
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* @ProjectName: shiro
* @Package: com.wzh.demo02
* @ClassName: MyRealm
* @Author: 王振华
* @Description:
* @Date: 2022/8/4 19:44
* @Version: 1.0
*/
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
private PermissionService permissionService;
@Autowired
private RoleService roleService;
@Override
//该方法用于完成认证的功能
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1.根据token获取账号
String username = (String) authenticationToken.getPrincipal();
/**
* 以前登陆的逻辑是 把用户和密码全部发到数据库 去匹配
* 在shrio里面是先根据用户名把用户对象查询出来,再来做密码匹配
*/
//2.根据账号查询用户信息
User user = userService.findByUsername(username);
//表示该用户名在数据库中存在
if(user!=null){
/**
* 参数说明
* 参数1:可以传到任意对象
* 参数2:从数据库里面查询出来的密码
* 参数3:盐
* 参数4:当前类名
*/
ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserpwd(),credentialsSalt,this.getName());
return info;
}
//用户不存在 shiro会抛 UnknowAccountException
return null;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//根据账号查找该用户具有哪些权限
List<String> list = permissionService.findPermissionById(user.getUserid());
if(list!=null&&list.size()>0){
info.addStringPermissions(list);
}
List<String> roles = roleService.findRolesById(user.getUserid());
if(roles!=null&&roles.size()>0){
info.addRoles(roles);
}
return info;
}
}
util:
CommonResult:
package com.wzh.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ProjectName: shiro-ssm0805
* @Package: com.wzh.utils
* @ClassName: CommonResult
* @Author: 王振华
* @Description:
* @Date: 2022/8/5 11:02
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResult {
public static final CommonResult UNLOGIN = new CommonResult(403,"未登录",null);
public static final CommonResult UNAUTHORIZED = new CommonResult(405,"未授权",null);
public static final CommonResult LOGIN_SUCCESS = new CommonResult(200,"登录成功",null);
public static final CommonResult LOGIN_ERROR = new CommonResult(-1,"登录失败",null);
private Integer code;
private String msg;
private Object data;
}