赞
踩
Shiro和Spring Security应该是我们比较常用的权限框架了,这篇文章教大家怎么通过springboot整合shiro从零开始搭建一个包含权限控制的后台管理系统。
目录
通过IntelliJ IDEA创建一个springboot项目,这里的项目就命名为springboot-shiro
修改pom.xml,添加相关的maven依赖
- <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.5.9</version>
- <relativePath />
- </parent>
-
- <groupId>cn.edu.sgu.www</groupId>
- <artifactId>springboot-shiro</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>springboot-shiro</name>
- <description>Spring Boot整合Shiro权限认证框架</description>
-
- <properties>
- <java.version>1.8</java.version>
- <shiro.version>1.3.2</shiro.version>
- <mysql.version>8.0.28</mysql.version>
- <druid.version>1.1.21</druid.version>
- <lombok.version>1.18.22</lombok.version>
- <fastjson.version>2.0.8</fastjson.version>
- <mybatis.version>2.2.2</mybatis.version>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <!--lombok-->
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>${lombok.version}</version>
- </dependency>
-
- <!--mysql-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>${mysql.version}</version>
- </dependency>
-
- <!--mybatis-->
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>${mybatis.version}</version>
- </dependency>
-
- <!--druid-->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>${druid.version}</version>
- </dependency>
-
- <!--fastjson-->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>${fastjson.version}</version>
- </dependency>
-
- <!-- shiro -->
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-spring</artifactId>
- <version>${shiro.version}</version>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- </project>
完成前面两步之后,删除多余的test包,项目结构如图:
修改系统的配置文件application.yml(修改默认的配置文件application.properties的名称为application.yml,只需要改后缀名),修改完成之后,把以下内容复制到application.yml中。
- spring:
- profiles:
- active: dev
-
- # mybatis的mapper.xml文件的位置
- mybatis:
- mapper-locations: classpath:mapper/*Mapper.xml
最后再新建一个application-dev.yml
- # 设置启动端口号
- server:
- port: 8080
-
- spring:
- # 配置数据源
- datasource:
- username: root
- password: root
- url: jdbc:mysql://localhost:3306/springboot-shiro
- driver-class-name: com.mysql.cj.jdbc.Driver
- type: com.alibaba.druid.pool.DruidDataSource
- # 只返回不为null的数据
- jackson:
- default-property-inclusion: non_null
1、通过navicat数据库连接工具新建数据库springboot-shiro,没有用过navicat的童鞋可以参考博主的文章推荐一款非常简单实用的数据库连接工具Navicat Premiumhttps://blog.csdn.net/heyl163_/article/details/132111378
2、在springboot-shiro数据库下创建用户表user
- -- ----------------------------
- -- Table structure for user
- -- ----------------------------
- DROP TABLE IF EXISTS `user`;
- CREATE TABLE `user` (
- `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
- `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
- `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
- `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '12345' COMMENT '密码',
- `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '手机号',
- `gender` tinyint(4) UNSIGNED NOT NULL COMMENT '性别',
- `is_enable` tinyint(4) UNSIGNED NOT NULL COMMENT '启用状态',
- `last_login_time` datetime NULL DEFAULT NULL COMMENT '上一次登录时间',
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
-
- -- ----------------------------
- -- Records of user
- -- ----------------------------
- INSERT INTO `user` VALUES ('2023', '系统管理员', 'system', '', '18888888888', 2, 1, '2022-11-25 00:15:42');
- INSERT INTO `user` VALUES ('mhxy1218', '沐雨橙风ιε', 'mumu', 'mhxy1218', '16666666666', 1, 1, '2023-07-02 00:00:29');
配置mapper包扫描路径
在springboot的启动类或者任意一个配置类上使用注解@MapperScan注解配置mybatis的mapper包扫描路径
@MapperScan("cn.edu.sgu.www.shiro.mapper")
在项目根目录下创建一个config包,在config包下面创建一个MybatisConfig类。
- package cn.edu.sgu.www.shiro.config;
-
- import org.mybatis.spring.annotation.MapperScan;
- import org.springframework.context.annotation.Configuration;
-
- /**
- * mybatis配置类
- * @author heyunlin
- * @version 1.0
- */
- @Configuration
- @MapperScan("cn.edu.sgu.www.shiro.mapper")
- public class MybatisConfig {
-
- }
项目根目录下创建realm包,在realm包下创建UserRealm.java,并继承AuthorizingRealm,实现AuthorizingRealm的两个认证和授权的抽象方法。
- package cn.edu.sgu.www.shiro.realm;
-
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.authc.AuthenticationInfo;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authz.AuthorizationInfo;
- import org.apache.shiro.realm.AuthorizingRealm;
- import org.apache.shiro.subject.PrincipalCollection;
- import org.springframework.stereotype.Component;
-
- /**
- * @author heyunlin
- * @version 1.0
- */
- @Component
- public class UserRealm extends AuthorizingRealm {
-
- /**
- * 认证
- */
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
- return null;
- }
-
- /**
- * 授权
- */
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- return null;
- }
-
- }
在config包下创建ShiroConfig.java
- package cn.edu.sgu.www.shiro.config;
-
- import cn.edu.sgu.www.shiro.realm.UserRealm;
- import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
- import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- /**
- * shiro配置类
- */
- @Configuration
- public class ShiroConfig {
-
- /**
- * 配置安全管理器
- * @param userRealm UserRealm
- * @return DefaultWebSecurityManager
- */
- @Bean
- public DefaultWebSecurityManager securityManager(UserRealm userRealm) {
- DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
-
- securityManager.setRealm(userRealm);
-
- return securityManager;
- }
-
- /**
- * 配置Shiro过滤器工厂
- * @param securityManager 安全管理器
- * @return ShiroFilterFactoryBean
- */
- @Bean
- public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
- ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
-
- // 注册安全管理器
- shiroFilterFactoryBean.setSecurityManager(securityManager);
-
- /*
- * 设置登录页面的地址
- * 当用户访问认证资源的时候,如果用户没有登录,那么就会跳转到该属性指定的页面
- */
- shiroFilterFactoryBean.setLoginUrl("/login.html");
-
- return shiroFilterFactoryBean;
- }
-
- }
在UserController类中添加一个login()方法,新建UserLoginDTO对象来接收前端传来的用户名和密码,同时通过validation验证这两个字段。
- package cn.edu.sgu.www.shiro.controller;
-
- import cn.edu.sgu.www.shiro.dto.UserLoginDTO;
- import cn.edu.sgu.www.shiro.restful.JsonResult;
- import cn.edu.sgu.www.shiro.service.UserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RestController;
-
- /**
- * @author heyunlin
- * @version 1.0
- */
- @RestController
- @RequestMapping(path = "/user", produces = "application/json;charset=utf-8")
- public class UserController {
-
- private final UserService userService;
-
- @Autowired
- public UserController(UserService userService) {
- this.userService = userService;
- }
-
- @RequestMapping(path = "/login", method = RequestMethod.POST)
- public JsonResult<Void> login(UserLoginDTO loginDTO) {
- userService.login(loginDTO);
-
- return JsonResult.success();
- }
-
- }
- package cn.edu.sgu.www.shiro.service;
-
- import cn.edu.sgu.www.shiro.dto.UserLoginDTO;
-
- /**
- * @author heyunlin
- * @version 1.0
- */
- public interface UserService {
-
- /**
- * 登录认证
- * @param loginDTO 登录信息
- */
- void login(UserLoginDTO loginDTO);
- }
UserServiceImpl中实现用户登录的业务代码,当我们调用Subject的login()方法时,会执行UserRealm下面的认证方法doGetAuthenticationInfo()
- package cn.edu.sgu.www.shiro.service.impl;
-
- import cn.edu.sgu.www.shiro.dto.UserLoginDTO;
- import cn.edu.sgu.www.shiro.entity.User;
- import cn.edu.sgu.www.shiro.exception.GlobalException;
- import cn.edu.sgu.www.shiro.mapper.UserMapper;
- import cn.edu.sgu.www.shiro.restful.ResponseCode;
- import cn.edu.sgu.www.shiro.service.UserService;
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.authc.UsernamePasswordToken;
- import org.apache.shiro.subject.Subject;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
-
- /**
- * @author heyunlin
- * @version 1.0
- */
- @Service
- public class UserServiceImpl implements UserService {
-
- private final UserMapper userMapper;
-
- @Autowired
- public UserServiceImpl(UserMapper userMapper) {
- this.userMapper = userMapper;
- }
-
- @Override
- public void login(UserLoginDTO loginDTO) {
- String username = loginDTO.getUsername();
-
- // 根据用户名查询用户信息
- User user = userMapper.selectByUsername(username);
-
- if (user != null) {
- if (user.getIsEnable()) {
- // shiro登录认证
- UsernamePasswordToken token = new UsernamePasswordToken(username, loginDTO.getPassword());
- Subject subject = SecurityUtils.getSubject();
-
- subject.login(token);
- // 设置session失效时间:永不超时
- subject.getSession().setTimeout(-1001);
- } else {
- throw new GlobalException(ResponseCode.FORBIDDEN, "账号已被锁定,禁止登录!");
- }
- } else {
- throw new GlobalException(ResponseCode.NOT_FOUND, "用户名不存在~");
- }
- }
-
- }
实现认证的方法,当调用Subject.login()方法时,在shiro框架内部会去调用realm的认证方法。
- package cn.edu.sgu.www.shiro.realm;
-
- import cn.edu.sgu.www.shiro.entity.User;
- import cn.edu.sgu.www.shiro.exception.GlobalException;
- import cn.edu.sgu.www.shiro.mapper.UserMapper;
- import cn.edu.sgu.www.shiro.restful.ResponseCode;
- import org.apache.shiro.authc.AuthenticationInfo;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authc.SimpleAuthenticationInfo;
- import org.apache.shiro.authc.UsernamePasswordToken;
- import org.apache.shiro.authz.AuthorizationInfo;
- import org.apache.shiro.realm.AuthorizingRealm;
- import org.apache.shiro.subject.PrincipalCollection;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
-
- /**
- * @author heyunlin
- * @version 1.0
- */
- @Component
- public class UserRealm extends AuthorizingRealm {
-
- private final UserMapper userMapper;
-
- @Autowired
- public UserRealm(UserMapper userMapper) {
- this.userMapper = userMapper;
- }
-
- /**
- * 认证
- */
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
- UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
-
- // 得到用户名
- String username = token.getUsername();
- // 根据用户名查询用户信息
- User user = userMapper.selectByUsername(username);
-
- if (user == null) {
- throw new GlobalException(ResponseCode.BAD_REQUEST, "登录失败,用户不存在~");
- }
- if (user.getIsEnable()) {
- String password = new String(token.getPassword());
-
- if (user.getPassword().equals(password)) {
- return new SimpleAuthenticationInfo(user, password, username);
- } else {
- throw new GlobalException(ResponseCode.BAD_REQUEST, "用户名或密码错误,登录失败!");
- }
- }
-
- return null;
- }
-
- /**
- * 授权
- */
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- return null;
- }
-
- }
UserMapper接口新增selectByUsername()方法
- package cn.edu.sgu.www.shiro.mapper;
-
- import cn.edu.sgu.www.shiro.entity.User;
- import org.springframework.stereotype.Repository;
-
- /**
- * @author heyunlin
- * @version 1.0
- */
- @Repository
- public interface UserMapper {
-
- /**
- * 根据用户名查询用户信息
- * @param username 用户名
- * @return User 查询到的用户信息
- */
- User selectByUsername(String username);
- }
通过xml的方式绑定sql语句
- <?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="cn.edu.sgu.www.shiro.mapper.UserMapper">
-
- <resultMap id="resultMap" type="cn.edu.sgu.www.shiro.entity.User">
- <result column="id" property="id" />
- <result column="name" property="name" />
- <result column="username" property="username" />
- <result column="password" property="password" />
- <result column="phone" property="phone" />
- <result column="is_enable" property="isEnable" />
- <result column="last_login_time" property="lastLoginTime" />
- </resultMap>
-
- <select id="selectByUsername" resultMap="resultMap">
- select * from user where username = #{username}
- </select>
- </mapper>
创建几个简单的页面试一下效果
准备工作:
在resources目录下创建static目录,存放静态资源文件,在static目录下创建js和html目录,把jquery.min.js复制到js目录下。
static目录下创建登录页面login.html
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>登录页面</title>
- </head>
-
- <body>
- <form id="loginForm">
- <table>
- <tr>
- <td>用户名</td>
- <td><input type="text" id="username" /></td>
- </tr>
-
- <tr>
- <td>密码</td>
- <td><input type="password" id="password" /></td>
- </tr>
-
- <tr>
- <td>
- <button type="button" id="login">登录</button>
- </td>
- <td>
- <button type="reset">重置</button>
- </td>
- </tr>
- </table>
- </form>
-
- <script src="/js/jquery.min.js"></script>
- <script src="/js/login.js"></script>
- </body>
- </html>
js目录下创建login.js,点击登录按钮时提交用户的数据到接口/user/login,完成登录操作
- $(document).ready(function () {
-
- $("#login").click(function () {
- let username = $("#username").val();
- let password = $("#password").val();
-
- $.post("/user/login", {
- username: username,
- password: password
- }, function (res) {
- if (res.code === 200) {
- location.href = "/html/home.html";
- }
- });
- });
-
- });
html目录下创建一个页面home.html
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>系统首页</title>
- </head>
-
- <body>
- <h1>欢迎来到系统首页!</h1>
- </body>
- </html>
添加资源访问规则,配置登录页面和登录接口的地址可以不需要登录认证就能访问,同时/html/home.html需要登录才能访问。
- package cn.edu.sgu.www.shiro.config;
-
- import cn.edu.sgu.www.shiro.realm.UserRealm;
- import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
- import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- import java.util.LinkedHashMap;
- import java.util.Map;
-
- /**
- * shiro配置类
- */
- @Configuration
- public class ShiroConfig {
-
- /**
- * 配置安全管理器
- * @param userRealm UserRealm
- * @return DefaultWebSecurityManager
- */
- @Bean
- public DefaultWebSecurityManager securityManager(UserRealm userRealm) {
- DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
-
- securityManager.setRealm(userRealm);
-
- return securityManager;
- }
-
- /**
- * 配置Shiro过滤器工厂
- * @param securityManager 安全管理器
- * @return ShiroFilterFactoryBean
- */
- @Bean
- public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
- ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
-
- // 注册安全管理器
- shiroFilterFactoryBean.setSecurityManager(securityManager);
-
- /*
- * 设置登录页面的地址
- * 当用户访问认证资源的时候,如果用户没有登录,那么就会跳转到指定的页面
- */
- shiroFilterFactoryBean.setLoginUrl("/login.html");
-
- // 定义资源访问规则
- Map<String, String> map = new LinkedHashMap<>();
-
- /*
- * 过滤器说明
- * anon:不需要认证就可以访问的资源
- * authc:需要登录认证才能访问的资源
- */
- map.put("/html/home.html", "authc");
-
- // 不需要认证就能访问
- map.put("/login.html", "anon");
- map.put("/user/login", "anon");
-
- shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
-
- return shiroFilterFactoryBean;
- }
-
- }
当我们访问localhost:8080/login.html时,输入mumu/mhxy1218,点击登录时,会跳转到/html/home.html。
然后我们清空浏览器缓存,刷新页面,发现页面重定向回了login.html。这是因为在shiro配置类里配置了/html/home.html要身份认证之后才能访问。
map.put("/html/home.html", "authc");
接下来,讲解如何通过shiro完成授权,在UserRealm里的doGetAuthorizationInfo()方法中实现授权的代码,查询用户的权限保存到shiro中,为了方便演示效果,我们模拟几条数据。
完成doGetAuthorizationInfo()方法的具体实现
- package cn.edu.sgu.www.shiro.realm;
-
- import cn.edu.sgu.www.shiro.entity.User;
- import cn.edu.sgu.www.shiro.exception.GlobalException;
- import cn.edu.sgu.www.shiro.mapper.UserMapper;
- import cn.edu.sgu.www.shiro.restful.ResponseCode;
- import org.apache.shiro.authc.AuthenticationInfo;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authc.SimpleAuthenticationInfo;
- import org.apache.shiro.authc.UsernamePasswordToken;
- 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 org.springframework.stereotype.Component;
-
- import java.util.HashSet;
- import java.util.Set;
-
- /**
- * @author heyunlin
- * @version 1.0
- */
- @Component
- public class UserRealm extends AuthorizingRealm {
-
- private final UserMapper userMapper;
-
- @Autowired
- public UserRealm(UserMapper userMapper) {
- this.userMapper = userMapper;
- }
-
- /**
- * 认证
- */
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
- UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
-
- // 得到用户名
- String username = token.getUsername();
- // 根据用户名查询用户信息
- User user = userMapper.selectByUsername(username);
-
- if (user == null) {
- throw new GlobalException(ResponseCode.BAD_REQUEST, "登录失败,用户不存在~");
- }
- if (user.getIsEnable()) {
- String password = new String(token.getPassword());
-
- if (user.getPassword().equals(password)) {
- return new SimpleAuthenticationInfo(user, password, username);
- } else {
- throw new GlobalException(ResponseCode.BAD_REQUEST, "用户名或密码错误,登录失败!");
- }
- }
-
- return null;
- }
-
- /**
- * 授权
- */
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
- Set<String> permissions = new HashSet<>();
-
- permissions.add("/user/delete");
- permissions.add("/user/update");
-
- authorizationInfo.setStringPermissions(permissions);
-
- return authorizationInfo;
- }
-
- }
在UserController中添加两个方法delete()和update()
- package cn.edu.sgu.www.shiro.controller;
-
- import cn.edu.sgu.www.shiro.dto.UserLoginDTO;
- import cn.edu.sgu.www.shiro.restful.JsonResult;
- import cn.edu.sgu.www.shiro.service.UserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RestController;
-
- /**
- * @author heyunlin
- * @version 1.0
- */
- @RestController
- @RequestMapping(path = "/user", produces = "application/json;charset=utf-8")
- public class UserController {
-
- private final UserService userService;
-
- @Autowired
- public UserController(UserService userService) {
- this.userService = userService;
- }
-
- @RequestMapping(path = "/login", method = RequestMethod.POST)
- public JsonResult<Void> login(UserLoginDTO loginDTO) {
- userService.login(loginDTO);
-
- return JsonResult.success();
- }
-
- @RequestMapping(path = "/delete", method = RequestMethod.POST)
- public JsonResult<Void> delete() {
- return JsonResult.success("删除成功");
- }
-
- @RequestMapping(path = "/update", method = RequestMethod.POST)
- public JsonResult<Void> update() {
- return JsonResult.success("修改成功");
- }
-
- }
home.html中新增两个按钮,同时还有引入jquery。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>系统首页</title>
- <script src="/js/jquery.min.js"></script>
- </head>
-
- <body>
- <h1>欢迎来到系统首页!</h1>
- <button type="button" id="delete">删除</button> | <button type="button" id="update">修改</button>
-
- <script>
- $(function () {
- $("#delete").click(function () {
- $.post("/user/delete", function (resp) {
- alert(resp.message);
- });
- });
-
- $("#update").click(function () {
- $.post("/user/update", function (resp) {
- alert(resp.message);
- });
- });
-
- });
- </script>
- </body>
- </html>
自定义过滤器AuthorizationFilter实现鉴权功能。
- package cn.edu.sgu.www.shiro.filter;
-
- import cn.edu.sgu.www.shiro.restful.JsonResult;
- import cn.edu.sgu.www.shiro.restful.ResponseCode;
- import com.alibaba.fastjson.JSON;
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.subject.Subject;
-
- import javax.servlet.*;
- import javax.servlet.annotation.WebFilter;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
-
- /**
- * 鉴权过滤器
- * @author heyunlin
- * @version 1.0
- */
- @WebFilter
- public class AuthorizationFilter implements Filter {
-
- @Override
- public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
- HttpServletRequest request = (HttpServletRequest) req;
- String requestURI = request.getRequestURI();
- Subject subject = SecurityUtils.getSubject();
-
- if (subject != null && !subject.isPermitted(requestURI)) {
- HttpServletResponse response = (HttpServletResponse) resp;
- response.setContentType("application/json;charset=utf-8");
-
- // 构建返回对象
- JsonResult<Void> jsonResult= JsonResult.error(ResponseCode.UNAUTHORIZED, "正在访问未授权的资源");
- String data = JSON.toJSONString(jsonResult);
-
- response.getWriter().write(data);
- return;
- }
-
- chain.doFilter(req, resp);
- }
-
- }
把自定义过滤器加入到shiro的过滤器链中,处理删除和修改两个接口。
map.put("/user/delete", "authorization");
map.put("/user/update", "authorization");
- package cn.edu.sgu.www.shiro.config;
-
- import cn.edu.sgu.www.shiro.filter.AuthorizationFilter;
- import cn.edu.sgu.www.shiro.realm.UserRealm;
- import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
- import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- import javax.servlet.Filter;
- import java.util.LinkedHashMap;
- import java.util.Map;
-
- /**
- * shiro配置类
- */
- @Configuration
- public class ShiroConfig {
-
- /**
- * 配置安全管理器
- * @param userRealm UserRealm
- * @return DefaultWebSecurityManager
- */
- @Bean
- public DefaultWebSecurityManager securityManager(UserRealm userRealm) {
- DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
-
- securityManager.setRealm(userRealm);
-
- return securityManager;
- }
-
- /**
- * 配置Shiro过滤器工厂
- * @param securityManager 安全管理器
- * @return ShiroFilterFactoryBean
- */
- @Bean
- public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
- ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
-
- // 注册安全管理器
- shiroFilterFactoryBean.setSecurityManager(securityManager);
-
- /*
- * 设置登录页面的地址
- * 当用户访问认证资源的时候,如果用户没有登录,那么就会跳转到指定的页面
- */
- shiroFilterFactoryBean.setLoginUrl("/login.html");
-
- // 定义资源访问规则
- Map<String, String> map = new LinkedHashMap<>();
-
- /*
- * 过滤器说明
- * anon:不需要认证就可以访问的资源
- * authc:需要登录认证才能访问的资源
- */
- map.put("/html/home.html", "authc");
-
- // 不需要认证就能访问
- map.put("/login.html", "anon");
- map.put("/user/login", "anon");
-
- // 设置自定义过滤器
- map.put("/user/delete", "authorization");
- map.put("/user/update", "authorization");
-
- shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
-
- Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
- filters.put("authorization", new AuthorizationFilter());
- shiroFilterFactoryBean.setFilters(filters);
-
- shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
-
- return shiroFilterFactoryBean;
- }
-
- }
为了测试,注释掉修改接口的资源权限,然后重启一下项目。
点击删除按钮会提升删除成功,但是修改的时候提示未授权。
好了,文章就分享到这里了,如果看完这篇文章感觉对你有所帮助,不要忘了点赞+收藏哦~
代码已经上传到git仓库,可按需获取:
springboot整合shiro实现认证和授权功能https://gitee.com/he-yunlin/springboot-shiro.git
更多代码详情,请参考博主的另一篇文章:
springboot整合shiro实现动态认证和授权https://blog.csdn.net/heyl163_/article/details/131518274
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。