使用shiro安全管理
之前介紹了springboot使用security進行許可權管理,這篇檔案介紹一下springboot使用shiro進行安全管理。
簡述本文的場景,本文使用springboot1.5.9+mysql+jpa+thymeleaf+shiro製作一個簡單的驗證,其中有2個角色,分別是admin和user,admin可以使用select和delete功能,user只能使用select功能。
新建專案,加入shiro依賴,pom檔案如下:
4.0.0 com.dalaoyang springboot_shiro 0.0.1-SNAPSHOT jar springboot_shiro springboot_shiro org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE <!-- lookup parent from repository -->UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-devtools runtime mysql mysql-connector-java runtime org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-thymeleaf net.sourceforge.nekohtml nekohtml 1.9.15 org.apache.shiro shiro-spring 1.4.0 org.springframework.boot spring-boot-maven-plugin
配置檔案如下:
##埠號
server.port=8888
##資料庫配置
##資料庫地址
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=utf8&useSSL=false
##資料庫使用者名稱
spring.datasource.username=root
##資料庫密碼
spring.datasource.password=root
##資料庫驅動
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
##validate 載入hibernate時,驗證建立資料庫表結構
##create 每次載入hibernate,重新建立資料庫表結構,這就是導致資料庫表資料丟失的原因。
##create-drop 載入hibernate時建立,退出是刪除表結構
##update 載入hibernate自動更新資料庫結構
##validate 啟動時驗證表的結構,不會建立表
##none 啟動時不做任何操作
spring.jpa.hibernate.ddl-auto=update
##控制檯列印sql
spring.jpa.show-sql=true
# 建議在開發時關閉快取,不然沒法看到實時頁面
spring.thymeleaf.cache=false
##去除thymeleaf的html嚴格校驗
spring.thymeleaf.mode=LEGACYHTML5
建立了三個實體類,分別是
SysUser(使用者表)
package com.dalaoyang.entity;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
/**
* @author dalaoyang
* @Description
* @project springboot_learn
* @package com.dalaoyang.entity
* @email yangyang@dalaoyang.cn
* @date 2018/5/2
*/
@Entity
public class SysUser implements Serializable {
@Id
@GeneratedValue
private Integer userId;
@NotEmpty
private String userName;
@NotEmpty
private String passWord;
//多對多關係
@ManyToMany(fetch= FetchType.EAGER)
//急載入,載入一個實體時,定義急載入的屬性會立即從資料庫中載入
//FetchType.LAZY:懶載入,載入一個實體時,定義懶載入的屬性不會馬上從資料庫中載入
@JoinTable(name = "SysUserRole", joinColumns = { @JoinColumn(name = "userId") },
inverseJoinColumns ={@JoinColumn(name = "roleId") })
private List roleList;// 一個使用者具有多個角色
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public List getRoleList() {
return roleList;
}
public void setRoleList(List roleList) {
this.roleList = roleList;
}
}
SysRole(角色表)
package com.dalaoyang.entity;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
/**
* @author dalaoyang
* @Description
* @project springboot_learn
* @package com.dalaoyang.entity
* @email yangyang@dalaoyang.cn
* @date 2018/5/2
*/
@Entity
public class SysRole implements Serializable {
@Id
@GeneratedValue
private Integer roleId;
private String roleName;
//多對多關係
@ManyToMany(fetch= FetchType.EAGER)
@JoinTable(name="SysRoleMenu",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="menuId")})
private List menuList;
//多對多關係
@ManyToMany
@JoinTable(name="SysUserRole",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="userId")})
private List userList;// 一個角色對應多個使用者
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public List getMenuList() {
return menuList;
}
public void setMenuList(List menuList) {
this.menuList = menuList;
}
public List getUserList() {
return userList;
}
public void setUserList(List userList) {
this.userList = userList;
}
}
SysMenu(選單表)
package com.dalaoyang.entity;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
/**
* @author dalaoyang
* @Description
* @project springboot_learn
* @package com.dalaoyang.entity
* @email yangyang@dalaoyang.cn
* @date 2018/5/2
*/
@Entity
public class SysMenu implements Serializable {
@Id
@GeneratedValue
private Integer menuId;
private String menuName;
@ManyToMany
@JoinTable(name="SysRoleMenu",joinColumns={@JoinColumn(name="menuId")},inverseJoinColumns={@JoinColumn(name="roleId")})
private List roleList;
public Integer getMenuId() {
return menuId;
}
public void setMenuId(Integer menuId) {
this.menuId = menuId;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public List getRoleList() {
return roleList;
}
public void setRoleList(List roleList) {
this.roleList = roleList;
}
}
建立一個UserRepository用於查詢使用者資訊:
package com.dalaoyang.repository;
import com.dalaoyang.entity.SysUser;
import org.springframework.data.repository.CrudRepository;
/**
* @author dalaoyang
* @Description
* @project springboot_learn
* @package com.dalaoyang.repository
* @email yangyang@dalaoyang.cn
* @date 2018/5/2
*/
public interface UserRepository extends CrudRepository {
SysUser findByUserName(String username);
}
建立幾個前臺頁面進行測試,分別是:
login.html:
Login
錯誤資訊:
index.html
Title
index
delete.html
Title
delete
select.html
Title
select
403.html
Title
403
建立一個ShiroConfig,程式碼如下:
package com.dalaoyang.config;
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 org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author dalaoyang
* @Description
* @project springboot_learn
* @package com.dalaoyang.config
* @email yangyang@dalaoyang.cn
* @date 2018/5/2
*/
@Configuration
public class ShiroConfig {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
logger.info("啟動shiroFilter--時間是:" + new Date());
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//shiro攔截器
Map filterChainDefinitionMap = new LinkedHashMap();
//<!-- authc:所有url都必須認證透過才可以訪問; anon:所有url都都可以匿名訪問-->
//<!-- 過濾鏈定義,從上向下順序執行,一般將/**放在最為下邊 -->
// 配置不被攔截的資源及連結
filterChainDefinitionMap.put("/static/**", "anon");
// 退出過濾器
filterChainDefinitionMap.put("/logout", "logout");
//配置需要認證許可權的
filterChainDefinitionMap.put("/**", "authc");
// 如果不設定預設會自動尋找Web工程根目錄下的"/login"頁面,即本文使用的login.html
shiroFilterFactoryBean.setLoginUrl("/login");
// 登入成功後要跳轉的連結
shiroFilterFactoryBean.setSuccessUrl("/index");
//未授權介面
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
//自定義身份認證Realm(包含使用者名稱密碼校驗,許可權校驗等)
@Bean
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
//開啟shiro aop註解支援,不開啟的話許可權驗證就會失效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
//配置異常處理,不配置的話沒有許可權後臺報錯,前臺不會跳轉到403頁面
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver
createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");//資料庫異常處理
mappings.setProperty("UnauthorizedException","403");
simpleMappingExceptionResolver.setExceptionMappings(mappings); // None by default
simpleMappingExceptionResolver.setDefaultErrorView("error"); // No default
simpleMappingExceptionResolver.setExceptionAttribute("ex"); // Default is "exception"
return simpleMappingExceptionResolver;
}
}
在配置一個MyShiroRealm用於登入認證和授權認證,程式碼如下:
package com.dalaoyang.config;
import com.dalaoyang.entity.SysMenu;
import com.dalaoyang.entity.SysRole;
import com.dalaoyang.entity.SysUser;
import com.dalaoyang.repository.UserRepository;
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 javax.annotation.Resource;
/**
* @author dalaoyang
* @Description
* @project springboot_learn
* @package com.dalaoyang.config
* @email yangyang@dalaoyang.cn
* @date 2018/5/2
*/
public class MyShiroRealm extends AuthorizingRealm {
@Resource
private UserRepository userRepository;
//授權
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
SysUser userInfo = (SysUser)principals.getPrimaryPrincipal();
for(SysRole role:userInfo.getRoleList()){
authorizationInfo.addRole(role.getRoleName());
for(SysMenu menu:role.getMenuList()){
authorizationInfo.addStringPermission(menu.getMenuName());
}
}
return authorizationInfo;
}
//認證
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
//獲得當前使用者的使用者名稱
String username = (String)token.getPrincipal();
System.out.println(token.getCredentials());
//根據使用者名稱找到物件
//實際專案中,這裡可以根據實際情況做快取,如果不做,Shiro自己也是有時間間隔機制,2分鐘內不會重複執行該方法
SysUser userInfo = userRepository.findByUserName(username);
if(userInfo == null){
return null;
}
//這裡會去校驗密碼是否正確
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, //使用者名稱
userInfo.getPassWord(),//密碼
getName()
);
return authenticationInfo;
}
}
最後新建一個controller,其中本文使用了2種驗證許可權的方法,select方法使用@RequiresPermissions("select")來驗證使用者是否具有select許可權,delete方法使用@RequiresRoles("admin")來驗證使用者是否是admin,程式碼如下:
package com.dalaoyang.controller;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* @author dalaoyang
* @Description
* @project springboot_learn
* @package com.dalaoyang.controller
* @email yangyang@dalaoyang.cn
* @date 2018/5/2
*/
@Controller
public class TestController {
@GetMapping({"/","/index"})
public String index(){
return"index";
}
@GetMapping("/403")
public String unauthorizedRole(){
return "403";
}
@GetMapping("/delete")
//@RequiresPermissions("delete")
@RequiresRoles("admin")
public String delete(){
return "delete";
}
@GetMapping("/select")
@RequiresPermissions("select")
public String select(){
return "select";
}
@RequestMapping("/login")
public String login(HttpServletRequest request, Map map) throws Exception{
System.out.println("HomeController.login()");
// 登入失敗從request中獲取shiro處理的異常資訊。
// shiroLoginFailure:就是shiro異常類的全類名.
String exception = (String) request.getAttribute("shiroLoginFailure");
String msg = "";
//根據異常判斷錯誤型別
if (exception != null) {
if (UnknownAccountException.class.getName().equals(exception)) {
msg = "賬號不存在";
} else if (IncorrectCredentialsException.class.getName().equals(exception)) {
msg = "密碼不正確";
} else {
msg = "else >> "+exception;
}
}
map.put("msg", msg);
// 此方法不處理登入成功,由shiro進行處理
return "/login";
}
@GetMapping("/logout")
public String logout(){
return "/login";
}
}
為了方便測試,本人插入了幾條初始資料,sql如下:
INSERT INTO `shiro`.`sys_menu`(`menu_id`, `menu_name`) VALUES (1, 'add');
INSERT INTO `shiro`.`sys_menu`(`menu_id`, `menu_name`) VALUES (2, 'delete');
INSERT INTO `shiro`.`sys_menu`(`menu_id`, `menu_name`) VALUES (3, 'update');
INSERT INTO `shiro`.`sys_menu`(`menu_id`, `menu_name`) VALUES (4, 'select');
INSERT INTO `shiro`.`sys_role`(`role_id`, `role_name`) VALUES (1, 'admin');
INSERT INTO `shiro`.`sys_role`(`role_id`, `role_name`) VALUES (2, 'user');
INSERT INTO `shiro`.`sys_role_menu`(`role_id`, `menu_id`) VALUES (1, 1);
INSERT INTO `shiro`.`sys_role_menu`(`role_id`, `menu_id`) VALUES (1, 2);
INSERT INTO `shiro`.`sys_role_menu`(`role_id`, `menu_id`) VALUES (1, 3);
INSERT INTO `shiro`.`sys_role_menu`(`role_id`, `menu_id`) VALUES (1, 4);
INSERT INTO `shiro`.`sys_role_menu`(`role_id`, `menu_id`) VALUES (2, 4);
INSERT INTO `shiro`.`sys_user`(`user_id`, `pass_word`, `user_name`) VALUES (1, '123', 'dalaoyang');
INSERT INTO `shiro`.`sys_user`(`user_id`, `pass_word`, `user_name`) VALUES (2, '123', 'xiaoli');
INSERT INTO `shiro`.`sys_user_role`(`role_id`, `user_id`) VALUES (1, 1);
INSERT INTO `shiro`.`sys_user_role`(`role_id`, `user_id`) VALUES (2, 2);
啟動專案,我在這裡就不一一截圖了,口述一下,訪問
如果使用角色為admin的使用者dalaoyang密碼123登入,以上請求全可以正常訪問。
原始碼下載 :大老楊碼雲
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2558/viewspace-2804711/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Shiro許可權管理框架(一):Shiro的基本使用框架
- 適合才最美:Shiro安全框架使用心得框架
- 關於shiro安全框架和shiro的認證流程框架
- 走進shiro,構建安全的應用程式---shiro修仙序章
- 學習springBoot(11)shiro安全框架Spring Boot框架
- 【Shiro第七篇】SpringBoot + Shiro實現會話管理Spring Boot會話
- SpringBoot與Shiro整合-許可權管理Spring Boot
- 28. 使用MySQL之安全管理MySql
- 使用semanage管理SELinux安全策略Linux
- shiro教程(1):基於url許可權管理
- Java安全之Shiro 550反序列化漏洞分析Java
- Shiro安全框架【快速入門】就這一篇!框架
- Shiro實現使用者授權
- SpringBoot中Shiro快取使用Redis、EhcacheSpring Boot快取Redis
- 【Shiro】4.Springboot整合ShiroSpring Boot
- Shiro-00-shiro 概覽
- shiro教程(2): shiro介紹
- 如何使用semanage管理SELinux安全策略Linux
- SpringBoot+Shiro學習(七):Filter過濾器管理Spring BootFilter過濾器
- Shiro許可權管理框架(二):Shiro結合Redis實現分散式環境下的Session共享框架Redis分散式Session
- web開發安全框架中的Apache Shiro的應用Web框架Apache
- spring-boot-plus整合Shiro+JWT許可權管理SpringbootJWT
- 備忘錄九:Spring Boot+Shiro許可權管理Spring Boot
- Spring Boot 整合 Shiro實現認證及授權管理Spring Boot
- 關於shiro+springMVC整合使用的問題SpringMVC
- Shiro系列教程之一Shiro簡介
- Shiro【授權、整合Spirng、Shiro過濾器】過濾器
- 【Shiro學習筆記】一、Shiro具體使用(基於springboot2.x,前後端分離)筆記Spring Boot後端
- 【shiro】11.shiro過濾器鑑權setFilterChainDefinitionMap過濾器FilterAI
- 【Shiro】5.多個Realm的使用和實現
- Shiro學習筆記(一) 基本概念與使用筆記
- shiro 整合MybatisMyBatis
- springboot-shiroSpring Boot
- spring-shiroSpring
- Docker安全管理Docker
- 在前後端分離專案中使用SpringBoot整合Shiro後端Spring Boot
- Shiro加鹽驗證/儲存使用者資訊
- springboot 許可權管理 後臺框架原始碼 java 專案 shiro FHAddminSpring Boot框架原始碼Java