SpringBoot中关于Shiro权限管理的整合使用

举报
tea_year 发表于 2021/12/22 23:34:24 2021/12/22
【摘要】 在整合Shiro的时候,我们先要确定一下我们的步骤: 1.加入Shiro的依赖包,实现自己的Realm类(通过继承AuthorizingRealm类); 2.实现Shiro的配置类 3.实现前端的登录界面以及Controller类   第一步: 在pom.xml中加入依赖包 <dependency> ...

在整合Shiro的时候,我们先要确定一下我们的步骤:

1.加入Shiro的依赖包,实现自己的Realm类(通过继承AuthorizingRealm类);

2.实现Shiro的配置类

3.实现前端的登录界面以及Controller类

 

第一步:

在pom.xml中加入依赖包


  
  1. <dependency>
  2. <groupId>org.apache.shiro</groupId>
  3. <artifactId>shiro-spring</artifactId>
  4. <version>1.4.0</version>
  5. </dependency>

实现Realm类


  
  1. package ariky.shiro.realm;
  2. import java.util.HashSet;
  3. import java.util.Set;
  4. import javax.servlet.http.HttpServletRequest;
  5. import org.apache.shiro.SecurityUtils;
  6. import org.apache.shiro.authc.AuthenticationException;
  7. import org.apache.shiro.authc.AuthenticationInfo;
  8. import org.apache.shiro.authc.AuthenticationToken;
  9. import org.apache.shiro.authc.IncorrectCredentialsException;
  10. import org.apache.shiro.authc.LockedAccountException;
  11. import org.apache.shiro.authc.SimpleAuthenticationInfo;
  12. import org.apache.shiro.authc.UsernamePasswordToken;
  13. import org.apache.shiro.authz.AuthorizationInfo;
  14. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  15. import org.apache.shiro.realm.AuthorizingRealm;
  16. import org.apache.shiro.subject.PrincipalCollection;
  17. import org.apache.shiro.util.ByteSource;
  18. import org.apache.shiro.web.subject.WebSubject;
  19. import org.slf4j.Logger;
  20. import org.slf4j.LoggerFactory;
  21. /**
  22. * @ClassName:
  23. * @Description: Realm的配置
  24. * @author fuweilian
  25. * @date 2018-5-12 上午11:36:41
  26. */
  27. public class MyShiroRealm extends AuthorizingRealm {
  28. //slf4j记录日志,可以不使用
  29. private Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);
  30. /**
  31. * 设置授权信息
  32. */
  33. @Override
  34. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  35. logger.info("开始授权(doGetAuthorizationInfo)");
  36. SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
  37. HttpServletRequest request = (HttpServletRequest) ((WebSubject) SecurityUtils
  38. .getSubject()).getServletRequest();//这个可以用来获取在登录的时候提交的其他额外的参数信息
  39. String username = (String) principals.getPrimaryPrincipal();//这里是写的demo,后面在实际项目中药通过这个登录的账号去获取用户的角色和权限,这里直接是写死的
  40. //受理权限
  41. //角色
  42. Set<String> roles = new HashSet<String>();
  43. roles.add("role1");
  44. authorizationInfo.setRoles(roles);
  45. //权限
  46. Set<String> permissions = new HashSet<String>();
  47. permissions.add("user:list");
  48. //permissions.add("user:add");
  49. authorizationInfo.setStringPermissions(permissions);
  50. return authorizationInfo;
  51. }
  52. /**
  53. * 设置认证信息
  54. */
  55. @Override
  56. protected AuthenticationInfo doGetAuthenticationInfo(
  57. AuthenticationToken authenticationToken) throws AuthenticationException {
  58. logger.info("开始认证(doGetAuthenticationInfo)");
  59. //UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
  60. HttpServletRequest request = (HttpServletRequest) ((WebSubject) SecurityUtils
  61. .getSubject()).getServletRequest();
  62. UsernamePasswordToken token = new UsernamePasswordToken (request.getParameter("userName"),request.getParameter("password"));
  63. //获取用户输入的账号
  64. String userName = (String)token.getPrincipal();
  65. //通过userName去数据库中匹配用户信息,通过查询用户的情况做下面的处理
  66. //这里暂时就直接写死,根据登录用户账号的情况做处理
  67. logger.info("账号:"+userName);
  68. if("passwordError".equals(userName)){//密码错误
  69. throw new IncorrectCredentialsException();
  70. }else if("lockAccount".equals(userName)){// 用户锁定
  71. throw new LockedAccountException();
  72. }else{
  73. SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
  74. userName, //用户名
  75. "123456", //密码,写死
  76. ByteSource.Util.bytes(userName+"salt"),//salt=username+salt
  77. getName() //realm name
  78. );
  79. return authenticationInfo;
  80. }
  81. }
  82. }

第二步 实现Shiro的配置类:


  
  1. package ariky.shiro.configuration;
  2. import java.util.LinkedHashMap;
  3. import java.util.Map;
  4. import org.apache.shiro.mgt.SecurityManager;
  5. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  6. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  7. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12. import ariky.shiro.realm.MyShiroRealm;
  13. /**
  14. * @ClassName: ShiroConfiguration
  15. * @Description: shiro的配置类
  16. * @author fuweilian
  17. * @date 2018-5-12 上午11:05:09
  18. */
  19. @Configuration
  20. public class ShiroConfiguration {
  21. private static Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);
  22. @Bean(name = "shiroFilter")
  23. public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
  24. logger.info("进入shiroFilter......");
  25. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  26. shiroFilterFactoryBean.setSecurityManager(securityManager);
  27. //设置不需要拦截的路径
  28. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
  29. //按顺序依次判断
  30. filterChainDefinitionMap.put("/static/**", "anon");
  31. //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
  32. filterChainDefinitionMap.put("/logout", "logout");
  33. //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
  34. /************************************初始化所有的权限信息开始******************************************/
  35. //这里,如果以后再项目中使用的话,直接从数据库中查询
  36. filterChainDefinitionMap.put("/user/list", "authc,perms[user:list]");
  37. //filterChainDefinitionMap.put("/user/add", "authc,perms[user:add]");
  38. /***************************************初始化所有的权限信息开始结束*********************************************/
  39. filterChainDefinitionMap.put("/**", "authc");
  40. // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
  41. shiroFilterFactoryBean.setLoginUrl("/login");
  42. // 登录成功后要跳转的链接
  43. shiroFilterFactoryBean.setSuccessUrl("/index");
  44. //未授权界面
  45. shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");
  46. shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
  47. return shiroFilterFactoryBean;
  48. }
  49. @Bean
  50. public MyShiroRealm myShiroRealm(){
  51. MyShiroRealm myShiroRealm = new MyShiroRealm();
  52. //后面这里可以设置缓存的机制
  53. return myShiroRealm;
  54. }
  55. @Bean
  56. public SecurityManager securityManager(){
  57. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  58. securityManager.setRealm(myShiroRealm());
  59. return securityManager;
  60. }
  61. @Bean
  62. public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
  63. AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
  64. authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
  65. return authorizationAttributeSourceAdvisor;
  66. }
  67. }

第三步:实现Controoler类,这里写俩个类,一个是登录信息的LoginController处理类,一个是测试权限用的UserController

1.LoginController.java


  
  1. package ariky.controller;
  2. import java.util.Map;
  3. import javax.servlet.http.HttpServletRequest;
  4. import org.apache.shiro.SecurityUtils;
  5. import org.apache.shiro.authc.IncorrectCredentialsException;
  6. import org.apache.shiro.authc.LockedAccountException;
  7. import org.apache.shiro.authc.UnknownAccountException;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10. import org.springframework.stereotype.Controller;
  11. import org.springframework.web.bind.annotation.RequestMapping;
  12. import org.springframework.web.bind.annotation.RequestMethod;
  13. /**
  14. * @ClassName: LoginController
  15. * @Description: 登录控制的controller
  16. * @author fuweilian
  17. * @date 2018-5-12 下午01:15:46
  18. */
  19. @RequestMapping
  20. @Controller
  21. public class LoginController {
  22. private Logger logger = LoggerFactory.getLogger(LoginController.class);
  23. @RequestMapping(value="/login",method=RequestMethod.GET)
  24. public String getLogin(){
  25. logger.info("进入login页面");
  26. return "login";
  27. }
  28. @RequestMapping(value="/login",method=RequestMethod.POST)
  29. public String doLogin(HttpServletRequest req,Map<String, Object> model){
  30. logger.info("进入登录处理");
  31. String exceptionClassName = (String) req.getAttribute("shiroLoginFailure");
  32. logger.info("exceptionClassName:"+exceptionClassName);
  33. String error = null;
  34. if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
  35. error = "用户名/密码错误";
  36. } else if (IncorrectCredentialsException.class.getName().equals(exceptionClassName)) {
  37. error = "用户名/密码错误";
  38. }else if(LockedAccountException.class.getName().equals(exceptionClassName)){
  39. error = "用户已锁定或已删除";
  40. }else if (exceptionClassName != null) {
  41. error = "其他错误:" + exceptionClassName;
  42. }
  43. if(SecurityUtils.getSubject().isAuthenticated()){//没有错误,但是已经登录了,就直接跳转到welcom页面
  44. model.put("name", req.getParameter("userName"));
  45. return "index";
  46. }else{//有错误的
  47. model.put("error", error);
  48. return "login";
  49. }
  50. }
  51. @RequestMapping("/index")
  52. public String index(){
  53. return "index";
  54. }
  55. }

2.UserController.java


  
  1. package ariky.controller;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import org.apache.shiro.authz.annotation.RequiresPermissions;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.stereotype.Controller;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.RequestMethod;
  10. import org.springframework.web.bind.annotation.ResponseBody;
  11. /**
  12. * @ClassName: UserController
  13. * @Description: 用户处理Controller
  14. * @author fuweilian
  15. * @date 2018-5-12 下午03:11:06
  16. */
  17. @Controller
  18. @RequestMapping("/user")
  19. public class UserController {
  20. Logger logger = LoggerFactory.getLogger(UserController.class);
  21. @RequiresPermissions("user:list")//这个是配置是否有该权限的,如果是按上面的写法,这个是有权限的
  22. @RequestMapping(value="/list",method=RequestMethod.GET)
  23. public String getList(){
  24. logger.info("进入用户列表");
  25. return "user/list";
  26. }
  27. @RequiresPermissions(value={"user:add"})//这个是没有权限的
  28. @RequestMapping(value="/add",method=RequestMethod.GET)
  29. public String getAdd(){
  30. logger.info("进入新增用户界面");
  31. return "user/add";
  32. }
  33. }

前端界面:有5个界面 (login.jsp,index.jsp,list.jsp,add.jsp,403.jsp)

目录结构为:

 

1.login.jsp


  
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  4. <html>
  5. <head>
  6. <title>Login</title>
  7. </head>
  8. <body>
  9. <h1>登录页面----${error}</h1>
  10. <form:form action="${pageContext.request.contextPath }/login"
  11. method="post">
  12. 用户名:<input type="text" name="userName">
  13. <br />
  14. 密码:<input type="passwordParam" name="password"/>
  15. <input type="submit" value="提交"/>
  16. </form:form>
  17. </body>
  18. </html>

2.index.jsp


  
  1. <%@ page language="java" pageEncoding="UTF-8"%>
  2. <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  4. <html>
  5. <head>
  6. <title>第一个例子</title>
  7. <script src="${pageContext.request.contextPath }/webjars/jquery/2.1.4/jquery.js"></script>
  8. <script src="${pageContext.request.contextPath }/webjarslocator/jquery/jquery.js"></script>
  9. </head>
  10. <body>
  11. <h1>${name}:你好,欢迎访问该网页</h1>
  12. <shiro:hasPermission name="user:list"><!-- 这个a标签是可以看见的 -->
  13. <a href="${pageContext.request.contextPath }/user/list" target="_blank">跳转到用户列表(有权限)</a>
  14. </shiro:hasPermission>
  15. <br/>
  16. <shiro:hasPermission name="user:add"><!-- 这个a标签是看不见的 -->
  17. <a href="${pageContext.request.contextPath }/user/add" target="_blank">跳转到新增用户列表(无权限)</a>
  18. </shiro:hasPermission>
  19. </body>
  20. </html>

3.list.jsp和add.jsp以及403.jsp都差不多一样,这里就写一个,这里只是demo所用,在实际项目中,要以实际项目为准


  
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  4. <html>
  5. <head>
  6. <title>userList</title>
  7. </head>
  8. <body>
  9. <h1>用户列表信息</h1>
  10. </body>
  11. </html>

如果启动成功,进入login登录界面就可以测试一下shiro的权限认证了。上面的代码都是写死的,如果想要实现动态的权限管理和用户的权限管理的话,还要做一些其他处理,用户的动态权限这个只要在自己的ShiroRealm类里面授权的时候做一下查询数据库,动态的授权和角色就行。关于动态的权限管理的话,下面的方式可以实现,在修改完权限数据后,更新一下shiro里面的配置就行,具体看下面的代码,这里是demo,不是实际项目,在实际项目中最好不要把逻辑写在Controller里面


  
  1. package ariky.shiro.controller;
  2. import java.util.LinkedHashMap;
  3. import java.util.Map;
  4. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  5. import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
  6. import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
  7. import org.apache.shiro.web.servlet.AbstractShiroFilter;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.stereotype.Controller;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.ResponseBody;
  12. /**
  13. * @ClassName: PermssionController
  14. * @Description: 权限操作的controller
  15. * @author fuweilian
  16. * @date 2018-5-12 下午04:59:15
  17. */
  18. @Controller
  19. @RequestMapping("permssion")
  20. public class PermssionController {
  21. @Autowired
  22. ShiroFilterFactoryBean shiroFilterFactoryBean;
  23. /**
  24. * @Title: updatePermssion
  25. * @author: fuweilian
  26. * @Description: 这里暂时直接写在controller里面,,不按规则写了,,到时候在项目中使用的时候,才写
  27. * @return 参数说明
  28. * @return Object 返回类型
  29. * @throws
  30. */
  31. @RequestMapping("/updatePermssion")
  32. @ResponseBody
  33. public Object updatePermssion(){
  34. synchronized (shiroFilterFactoryBean){
  35. AbstractShiroFilter shiroFilter = null;
  36. try {
  37. shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean
  38. .getObject();
  39. PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
  40. .getFilterChainResolver();
  41. DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver
  42. .getFilterChainManager();
  43. // 清空老的权限控制
  44. manager.getFilterChains().clear();
  45. shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
  46. //后面这个可以直接从数据库里面获取
  47. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
  48. //按顺序依次判断
  49. filterChainDefinitionMap.put("/static/**", "anon");
  50. //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
  51. filterChainDefinitionMap.put("/logout", "logout");
  52. //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
  53. /************************************初始化所有的权限信息开始******************************************/
  54. //这里,如果以后再项目中使用的话,直接从数据库中查询
  55. filterChainDefinitionMap.put("/user/list", "authc,perms[user:list]");
  56. filterChainDefinitionMap.put("/user/add", "authc,perms[user:add]");
  57. /***************************************初始化所有的权限信息开始结束*********************************************/
  58. filterChainDefinitionMap.put("/**", "authc");
  59. //
  60. shiroFilterFactoryBean.setLoginUrl("/login");
  61. // 登录成功后要跳转的链接
  62. shiroFilterFactoryBean.setSuccessUrl("/index");
  63. //未授权界面
  64. shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");
  65. shiroFilterFactoryBean
  66. .setFilterChainDefinitionMap(filterChainDefinitionMap);
  67. // 重新构建生成
  68. Map<String, String> chains = shiroFilterFactoryBean
  69. .getFilterChainDefinitionMap();
  70. for (Map.Entry<String, String> entry : chains.entrySet()) {
  71. String url = entry.getKey();
  72. String chainDefinition = entry.getValue().trim()
  73. .replace(" ", "");
  74. manager.createChain(url, chainDefinition);
  75. }
  76. return "更新权限成功";
  77. } catch (Exception e) {
  78. throw new RuntimeException(
  79. "更新shiro权限出现错误!");
  80. }
  81. }
  82. }
  83. }

  
  1. /*
  2. Navicat MySQL Data Transfer
  3. Source Server : arikyDB
  4. Source Server Version : 50721
  5. Source Host : 47.106.95.168:3306
  6. Source Database : ariky
  7. Target Server Type : MYSQL
  8. Target Server Version : 50721
  9. File Encoding : 65001
  10. Date: 2018-05-14 16:05:51
  11. */
  12. SET FOREIGN_KEY_CHECKS=0;
  13. -- ----------------------------
  14. -- Table structure for common_permssion
  15. -- ----------------------------
  16. DROP TABLE IF EXISTS `common_permssion`;
  17. CREATE TABLE `common_permssion` (
  18. `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  19. `NAME` varchar(255) DEFAULT NULL COMMENT '权限名称',
  20. `TYPE` varchar(255) DEFAULT NULL COMMENT '类型按钮(button)或者菜单(menu) ',
  21. `PARENT_ID` int(11) DEFAULT NULL COMMENT '上级ID',
  22. `PARENT_IDS` varchar(255) DEFAULT NULL COMMENT '上级PIDs',
  23. `URL` varchar(255) DEFAULT NULL COMMENT '访问路径',
  24. `ICONCLS` varchar(255) DEFAULT NULL COMMENT '图标(可以不要)',
  25. `PERMISSION` varchar(255) DEFAULT NULL COMMENT '权限(如user:list)',
  26. `ORDER_NUM` int(11) DEFAULT NULL COMMENT '排序',
  27. `REMARK` varchar(255) DEFAULT NULL COMMENT '备注',
  28. PRIMARY KEY (`ID`)
  29. ) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8 COMMENT='该表用来存储资源权限信息';
  30. -- ----------------------------
  31. -- Table structure for common_role
  32. -- ----------------------------
  33. DROP TABLE IF EXISTS `common_role`;
  34. CREATE TABLE `common_role` (
  35. `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  36. `LABEL_ID` varchar(255) DEFAULT NULL COMMENT '标签Id',
  37. `NAME` varchar(255) DEFAULT NULL COMMENT '角色名称',
  38. `ROLE` varchar(255) DEFAULT NULL,
  39. `DESCRIPTION` varchar(255) DEFAULT NULL,
  40. `IS_SHOW` int(11) DEFAULT '1' COMMENT '判断该角色是否在使用(1:使用,2:禁用)',
  41. `IS_HANDLER` int(2) DEFAULT NULL COMMENT '判断是什么角色(1:后台角色,2:商家管理员角色,3:商家添加用户角色,4:游客角色)',
  42. PRIMARY KEY (`ID`)
  43. ) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='角色表';
  44. -- ----------------------------
  45. -- Table structure for common_role_permssion
  46. -- ----------------------------
  47. DROP TABLE IF EXISTS `common_role_permssion`;
  48. CREATE TABLE `common_role_permssion` (
  49. `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
  50. `ROLE_ID` int(11) DEFAULT NULL COMMENT '角色Id',
  51. `RESOURCE_ID` int(11) DEFAULT NULL COMMENT '资源(权限)Id',
  52. PRIMARY KEY (`ID`)
  53. ) ENGINE=InnoDB AUTO_INCREMENT=493 DEFAULT CHARSET=utf8 COMMENT='角色资源权限表中间表';

 

文章来源: aaaedu.blog.csdn.net,作者:tea_year,版权归原作者所有,如需转载,请联系作者。

原文链接:aaaedu.blog.csdn.net/article/details/104625839

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。