javascript
SpringBoot中关于Shiro权限管理的整合使用
在整合Shiro的時候,我們先要確定一下我們的步驟:
1.加入Shiro的依賴包,實現自己的Realm類(通過繼承AuthorizingRealm類);
2.實現Shiro的配置類
3.實現前端的登錄界面以及Controller類
?
第一步:
在pom.xml中加入依賴包
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.4.0</version></dependency>實現Realm類
package ariky.shiro.realm;import java.util.HashSet; import java.util.Set;import javax.servlet.http.HttpServletRequest;import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; 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.apache.shiro.util.ByteSource; import org.apache.shiro.web.subject.WebSubject; import org.slf4j.Logger; import org.slf4j.LoggerFactory;/** * @ClassName: * @Description: Realm的配置 * @author fuweilian * @date 2018-5-12 上午11:36:41*/ public class MyShiroRealm extends AuthorizingRealm {//slf4j記錄日志,可以不使用private Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);/*** 設置授權信息*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {logger.info("開始授權(doGetAuthorizationInfo)");SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();HttpServletRequest request = (HttpServletRequest) ((WebSubject) SecurityUtils.getSubject()).getServletRequest();//這個可以用來獲取在登錄的時候提交的其他額外的參數信息String username = (String) principals.getPrimaryPrincipal();//這里是寫的demo,后面在實際項目中藥通過這個登錄的賬號去獲取用戶的角色和權限,這里直接是寫死的//受理權限//角色Set<String> roles = new HashSet<String>();roles.add("role1");authorizationInfo.setRoles(roles);//權限Set<String> permissions = new HashSet<String>();permissions.add("user:list");//permissions.add("user:add");authorizationInfo.setStringPermissions(permissions);return authorizationInfo;}/*** 設置認證信息*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {logger.info("開始認證(doGetAuthenticationInfo)");//UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;HttpServletRequest request = (HttpServletRequest) ((WebSubject) SecurityUtils.getSubject()).getServletRequest();UsernamePasswordToken token = new UsernamePasswordToken (request.getParameter("userName"),request.getParameter("password"));//獲取用戶輸入的賬號String userName = (String)token.getPrincipal();//通過userName去數據庫中匹配用戶信息,通過查詢用戶的情況做下面的處理//這里暫時就直接寫死,根據登錄用戶賬號的情況做處理logger.info("賬號:"+userName);if("passwordError".equals(userName)){//密碼錯誤throw new IncorrectCredentialsException(); }else if("lockAccount".equals(userName)){// 用戶鎖定throw new LockedAccountException(); }else{SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, //用戶名"123456", //密碼,寫死ByteSource.Util.bytes(userName+"salt"),//salt=username+saltgetName() //realm name);return authenticationInfo;}}}第二步 實現Shiro的配置類:
package ariky.shiro.configuration;import java.util.LinkedHashMap; import java.util.Map;import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import ariky.shiro.realm.MyShiroRealm;/** * @ClassName: ShiroConfiguration * @Description: shiro的配置類 * @author fuweilian * @date 2018-5-12 上午11:05:09*/ @Configuration public class ShiroConfiguration {private static Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);@Bean(name = "shiroFilter")public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){logger.info("進入shiroFilter......");ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);//設置不需要攔截的路徑Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String, String>();//按順序依次判斷filterChainDefinitionMap.put("/static/**", "anon");//配置退出 過濾器,其中的具體的退出代碼Shiro已經替我們實現了filterChainDefinitionMap.put("/logout", "logout");//<!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問-->/************************************初始化所有的權限信息開始******************************************///這里,如果以后再項目中使用的話,直接從數據庫中查詢filterChainDefinitionMap.put("/user/list", "authc,perms[user:list]");//filterChainDefinitionMap.put("/user/add", "authc,perms[user:add]");/***************************************初始化所有的權限信息開始結束*********************************************/filterChainDefinitionMap.put("/**", "authc");// 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面shiroFilterFactoryBean.setLoginUrl("/login");// 登錄成功后要跳轉的鏈接shiroFilterFactoryBean.setSuccessUrl("/index");//未授權界面shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}@Beanpublic MyShiroRealm myShiroRealm(){MyShiroRealm myShiroRealm = new MyShiroRealm();//后面這里可以設置緩存的機制return myShiroRealm;} @Beanpublic SecurityManager securityManager(){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(myShiroRealm());return securityManager;}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}}第三步:實現Controoler類,這里寫倆個類,一個是登錄信息的LoginController處理類,一個是測試權限用的UserController
1.LoginController.java
package ariky.controller;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;/** * @ClassName: LoginController * @Description: 登錄控制的controller * @author fuweilian * @date 2018-5-12 下午01:15:46*/ @RequestMapping @Controller public class LoginController {private Logger logger = LoggerFactory.getLogger(LoginController.class);@RequestMapping(value="/login",method=RequestMethod.GET)public String getLogin(){logger.info("進入login頁面");return "login";}@RequestMapping(value="/login",method=RequestMethod.POST)public String doLogin(HttpServletRequest req,Map<String, Object> model){logger.info("進入登錄處理");String exceptionClassName = (String) req.getAttribute("shiroLoginFailure");logger.info("exceptionClassName:"+exceptionClassName);String error = null;if (UnknownAccountException.class.getName().equals(exceptionClassName)) {error = "用戶名/密碼錯誤";} else if (IncorrectCredentialsException.class.getName().equals(exceptionClassName)) {error = "用戶名/密碼錯誤";}else if(LockedAccountException.class.getName().equals(exceptionClassName)){ error = "用戶已鎖定或已刪除";}else if (exceptionClassName != null) {error = "其他錯誤:" + exceptionClassName;}if(SecurityUtils.getSubject().isAuthenticated()){//沒有錯誤,但是已經登錄了,就直接跳轉到welcom頁面model.put("name", req.getParameter("userName"));return "index";}else{//有錯誤的model.put("error", error);return "login";}}@RequestMapping("/index")public String index(){return "index";} }2.UserController.java
package ariky.controller;import java.util.ArrayList; import java.util.List;import org.apache.shiro.authz.annotation.RequiresPermissions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody;/** * @ClassName: UserController * @Description: 用戶處理Controller * @author fuweilian * @date 2018-5-12 下午03:11:06*/ @Controller @RequestMapping("/user") public class UserController {Logger logger = LoggerFactory.getLogger(UserController.class);@RequiresPermissions("user:list")//這個是配置是否有該權限的,如果是按上面的寫法,這個是有權限的@RequestMapping(value="/list",method=RequestMethod.GET)public String getList(){logger.info("進入用戶列表");return "user/list";}@RequiresPermissions(value={"user:add"})//這個是沒有權限的@RequestMapping(value="/add",method=RequestMethod.GET)public String getAdd(){logger.info("進入新增用戶界面");return "user/add";}}前端界面:有5個界面 (login.jsp,index.jsp,list.jsp,add.jsp,403.jsp)
目錄結構為:
?
1.login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Login</title> </head><body><h1>登錄頁面----${error}</h1><form:form action="${pageContext.request.contextPath }/login"method="post">用戶名:<input type="text" name="userName"><br />密碼:<input type="passwordParam" name="password"/><input type="submit" value="提交"/></form:form> </body> </html>2.index.jsp
<%@ page language="java" pageEncoding="UTF-8"%><%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>第一個例子</title> <script src="${pageContext.request.contextPath }/webjars/jquery/2.1.4/jquery.js"></script> <script src="${pageContext.request.contextPath }/webjarslocator/jquery/jquery.js"></script> </head><body><h1>${name}:你好,歡迎訪問該網頁</h1><shiro:hasPermission name="user:list"><!-- 這個a標簽是可以看見的 --><a href="${pageContext.request.contextPath }/user/list" target="_blank">跳轉到用戶列表(有權限)</a></shiro:hasPermission><br/><shiro:hasPermission name="user:add"><!-- 這個a標簽是看不見的 --><a href="${pageContext.request.contextPath }/user/add" target="_blank">跳轉到新增用戶列表(無權限)</a></shiro:hasPermission> </body> </html>3.list.jsp和add.jsp以及403.jsp都差不多一樣,這里就寫一個,這里只是demo所用,在實際項目中,要以實際項目為準
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>userList</title> </head><body><h1>用戶列表信息</h1> </body> </html>如果啟動成功,進入login登錄界面就可以測試一下shiro的權限認證了。上面的代碼都是寫死的,如果想要實現動態的權限管理和用戶的權限管理的話,還要做一些其他處理,用戶的動態權限這個只要在自己的ShiroRealm類里面授權的時候做一下查詢數據庫,動態的授權和角色就行。關于動態的權限管理的話,下面的方式可以實現,在修改完權限數據后,更新一下shiro里面的配置就行,具體看下面的代碼,這里是demo,不是實際項目,在實際項目中最好不要把邏輯寫在Controller里面
package ariky.shiro.controller;import java.util.LinkedHashMap; import java.util.Map;import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager; import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; import org.apache.shiro.web.servlet.AbstractShiroFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;/** * @ClassName: PermssionController * @Description: 權限操作的controller * @author fuweilian * @date 2018-5-12 下午04:59:15*/ @Controller @RequestMapping("permssion") public class PermssionController {@AutowiredShiroFilterFactoryBean shiroFilterFactoryBean;/*** @Title: updatePermssion * @author: fuweilian* @Description: 這里暫時直接寫在controller里面,,不按規則寫了,,到時候在項目中使用的時候,才寫* @return 參數說明 * @return Object 返回類型 * @throws*/@RequestMapping("/updatePermssion")@ResponseBodypublic Object updatePermssion(){synchronized (shiroFilterFactoryBean){AbstractShiroFilter shiroFilter = null;try {shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();// 清空老的權限控制manager.getFilterChains().clear();shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();//后面這個可以直接從數據庫里面獲取Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String, String>();//按順序依次判斷filterChainDefinitionMap.put("/static/**", "anon");//配置退出 過濾器,其中的具體的退出代碼Shiro已經替我們實現了filterChainDefinitionMap.put("/logout", "logout");//<!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問-->/************************************初始化所有的權限信息開始******************************************///這里,如果以后再項目中使用的話,直接從數據庫中查詢filterChainDefinitionMap.put("/user/list", "authc,perms[user:list]");filterChainDefinitionMap.put("/user/add", "authc,perms[user:add]");/***************************************初始化所有的權限信息開始結束*********************************************/filterChainDefinitionMap.put("/**", "authc");//shiroFilterFactoryBean.setLoginUrl("/login");// 登錄成功后要跳轉的鏈接shiroFilterFactoryBean.setSuccessUrl("/index");//未授權界面shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);// 重新構建生成Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();for (Map.Entry<String, String> entry : chains.entrySet()) {String url = entry.getKey();String chainDefinition = entry.getValue().trim().replace(" ", "");manager.createChain(url, chainDefinition);}return "更新權限成功"; } catch (Exception e) {throw new RuntimeException("更新shiro權限出現錯誤!");}}}} /* Navicat MySQL Data Transfer Source Server : arikyDB Source Server Version : 50721 Source Host : 47.106.95.168:3306 Source Database : ariky Target Server Type : MYSQL Target Server Version : 50721 File Encoding : 65001 Date: 2018-05-14 16:05:51 */SET FOREIGN_KEY_CHECKS=0;-- ---------------------------- -- Table structure for common_permssion -- ---------------------------- DROP TABLE IF EXISTS `common_permssion`; CREATE TABLE `common_permssion` (`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',`NAME` varchar(255) DEFAULT NULL COMMENT '權限名稱',`TYPE` varchar(255) DEFAULT NULL COMMENT '類型按鈕(button)或者菜單(menu) ',`PARENT_ID` int(11) DEFAULT NULL COMMENT '上級ID',`PARENT_IDS` varchar(255) DEFAULT NULL COMMENT '上級PIDs',`URL` varchar(255) DEFAULT NULL COMMENT '訪問路徑',`ICONCLS` varchar(255) DEFAULT NULL COMMENT '圖標(可以不要)',`PERMISSION` varchar(255) DEFAULT NULL COMMENT '權限(如user:list)',`ORDER_NUM` int(11) DEFAULT NULL COMMENT '排序',`REMARK` varchar(255) DEFAULT NULL COMMENT '備注',PRIMARY KEY (`ID`) ) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8 COMMENT='該表用來存儲資源權限信息';-- ---------------------------- -- Table structure for common_role -- ---------------------------- DROP TABLE IF EXISTS `common_role`; CREATE TABLE `common_role` (`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',`LABEL_ID` varchar(255) DEFAULT NULL COMMENT '標簽Id',`NAME` varchar(255) DEFAULT NULL COMMENT '角色名稱',`ROLE` varchar(255) DEFAULT NULL,`DESCRIPTION` varchar(255) DEFAULT NULL,`IS_SHOW` int(11) DEFAULT '1' COMMENT '判斷該角色是否在使用(1:使用,2:禁用)',`IS_HANDLER` int(2) DEFAULT NULL COMMENT '判斷是什么角色(1:后臺角色,2:商家管理員角色,3:商家添加用戶角色,4:游客角色)',PRIMARY KEY (`ID`) ) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='角色表';-- ---------------------------- -- Table structure for common_role_permssion -- ---------------------------- DROP TABLE IF EXISTS `common_role_permssion`; CREATE TABLE `common_role_permssion` (`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵Id',`ROLE_ID` int(11) DEFAULT NULL COMMENT '角色Id',`RESOURCE_ID` int(11) DEFAULT NULL COMMENT '資源(權限)Id',PRIMARY KEY (`ID`) ) ENGINE=InnoDB AUTO_INCREMENT=493 DEFAULT CHARSET=utf8 COMMENT='角色資源權限表中間表';?
總結
以上是生活随笔為你收集整理的SpringBoot中关于Shiro权限管理的整合使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 飞机大战-控制飞机左右移动二
- 下一篇: 郑州大学软件学院 大学生创新创业选拔赛