SpringBoot整合Shiro實現登錄認證,鑒權授權

文章目錄

  • 前言
  • 一、shiro簡介
  • 二、環境搭建
    • 2.1.數據庫
      • 2.1.1user用戶表
      • 2.1.2user_role用戶角色關系表
      • 2.1.3role角色表
      • 2.1.4role_permission角色權限關系表
      • 2.1.5permission權限表
    • 2.2導坐標
    • 2.3實體類
      • 2.3.1User
      • 2.3.2Role
      • 2.3.3Permission
    • 2.4MVC三層
      • 2.4.1User
        • 2.4.1.1mapper層
        • 2.4.1.2service層
        • 2.4.1.3controller層
      • 2.4.2Role
        • 2.4.2.1mapper層
        • 2.4.2.2service層
        • 2.4.2.3controller層
      • 2.3.3Permission
        • 2.4.3.1mapper層
        • 2.4.3.2service層
        • 2.4.3.3controller層
    • 2.5.加密工具類
    • 2.6.全局異常處理器
    • 2.7自定義Realm
    • 2.8shiro配置類
  • 三、案例演示
    • 3.1 登錄認證
    • 3.2 權限認證
  • 總結


前言

近期對Springboot框架的學習中,為了更好的學習理解Springsecurity中間件,先學習了一下“老派”的shiro安全框架,本文章將通過注解的方式實現基礎的用戶認證和角色授權案例

一、shiro簡介

Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼和會話管理。使用Shiro的易于理解的API,您可以快速、輕松地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序。

二、環境搭建

2.1.數據庫

2.1.1user用戶表

在這里插入圖片描述

2.1.2user_role用戶角色關系表

在這里插入圖片描述

2.1.3role角色表

在這里插入圖片描述

2.1.4role_permission角色權限關系表

在這里插入圖片描述

2.1.5permission權限表

在這里插入圖片描述

2.2導坐標

<properties><java.version>1.8</java.version><!--shiro--><shiro.version>1.3.2</shiro.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><!-- SECURITY begin --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>${shiro.version}</version></dependency><!-- SECURITY end --></dependencies>

2.3實體類

2.3.1User

@TableName("pe_user")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {@TableId(value = "id",type = IdType.AUTO)private int id;private String username;private String password;private String salt;@TableField(exist = false)private Set<Role> roles;
}

2.3.2Role

@TableName("pe_role")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {@TableId(value = "id",type = IdType.AUTO)private int id;private String name;private String code;private String description;@TableField(exist = false)private Set<Permission> permissions;
}

2.3.3Permission

@TableName("pe_permission")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Permission {@TableId(value = "id",type = IdType.AUTO)private int id;private String name;private String code;private String description;
}

2.4MVC三層

2.4.1User

2.4.1.1mapper層

public interface UserMapper extends BaseMapper<User> {@Select("select * from pe_user where username = #{name}")User findUserByName(String name);//級聯查詢@Results({@Result(column = "id",property = "id"),@Result(column = "username",property = "username"),@Result(column = "password",property = "password"),@Result(column = "salt",property = "salt"),@Result(column = "id",property = "roles",many=@Many(select = "com.apesource.shirostudy_demo_05.dao.RoleMapper.findRoleIdsByUserId"))})@Select("select * from pe_user where id = #{id}")User findUserDetailById(@Param("id") int id);
}

2.4.1.2service層

public interface IUserService extends IService<User> {User findUserByName(String name);User findUserDetailById(int id);
}@Service
@SuppressWarnings("all")
public class UserServiceImp extends ServiceImpl<UserMapper, User> implements IUserService {@AutowiredUserMapper userMapper;@AutowiredIRoleService roleService;@Overridepublic User findUserByName(String name) {User user = userMapper.findUserByName(name);return user;}@Overridepublic User findUserDetailById(int id) {//根據userid查詢userUser user = userMapper.findUserDetailById(id);//返回return user;}
}

2.4.1.3controller層

@RestController
public class UserController {@Autowiredprivate IUserService userService;//個人主頁@RequiresPermissions("user-home")@RequestMapping(value = "/user/home")public String home() {return "訪問個人主頁成功";}//根據名字查詢用戶基本信息@RequiresPermissions("user-find")@RequestMapping(value = "/user/userByName/{name}")public String findUserByName(@PathVariable String name) {System.out.println(name);User user = userService.findUserByName(name);return user.toString();}//更新@RequiresPermissions("user-update")@RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)public String update(@PathVariable String id) {return "更新用戶成功";}//刪除@RequiresPermissions("user-delete")@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)public String delete(@PathVariable String id) {return "刪除用戶成功";}//根據id查詢用戶詳細信息@RequiresPermissions("user-find")@RequestMapping(value = "/user/userById/{id}")public String findUserDetailById(@PathVariable int id) {return userService.findUserDetailById(id).toString();}//登錄頁面@RequestMapping(value = "/login")public String login(User user) {try {//1.構造登錄令牌UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());//2.//2.獲取subjectSubject subject = SecurityUtils.getSubject();//3.調用subject進行登錄subject.login(token);return "登錄成功!!!";} catch (AuthenticationException e) {return "用戶名或密碼錯誤!!!";}}//未登陸與未授權頁面@RequestMapping(value = "/autherror")public String autherror() {return "未登錄";}}

2.4.2Role

2.4.2.1mapper層

public interface RoleMapper extends BaseMapper<Role> {@Results({@Result(column = "id",property = "id"),@Result(column = "name",property = "name"),@Result(column = "code",property = "code"),@Result(column = "description",property = "description"),@Result(column = "id",property = "permissions",many =@Many(select = "com.apesource.shirostudy_demo_05.dao.PermissionMapper.findPermissionIdsByRoleId"))})@Select("SELECT * FROM pe_role WHERE id IN (SELECT role_id FROM pe_user_role WHERE user_id = #{id})")Set<Role> findRoleIdsByUserId(int id);
}

2.4.2.2service層

public interface IRoleService extends IService<Role> {Set<Role> findRoleIdsByUserId(int id);
}
@Service
@SuppressWarnings("all")
public class RoleServiceImp extends ServiceImpl<RoleMapper, Role> implements IRoleService {@AutowiredRoleMapper roleMapper;@AutowiredIPermissionService permissionService;@Overridepublic Set<Role> findRoleIdsByUserId(int id) {Set<Role> roles = roleMapper.findRoleIdsByUserId(id);return roles;}
}

2.4.2.3controller層

由于不演示,無。

2.3.3Permission

2.4.3.1mapper層

public interface PermissionMapper extends BaseMapper<Permission> {@Results({@Result(column = "id",property = "id"),@Result(column = "name",property = "name"),@Result(column = "code",property = "code"),@Result(column = "description",property = "description"),})@Select("SELECT * FROM pe_permission WHERE id IN (SELECT permission_id FROM pe_role_permission WHERE role_id = #{id} ) ")Set<Permission> findPermissionIdsByRoleId(int id);
}

2.4.3.2service層

public interface IPermissionService extends IService<Permission> {Set<Permission> findPermissionIdsByRoleId(int id);
}
@Service
public class PermissionServiceImp extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {@Autowired(required = false)PermissionMapper permissionMapper;@Overridepublic Set<Permission> findPermissionIdsByRoleId(int id) {Set<Permission> permissionIds = permissionMapper.findPermissionIdsByRoleId(id);return permissionIds;}
}

2.4.3.3controller層

由于不演示,無。

2.5.加密工具類

public class DigestsUtil {public static final String SHA1 = "SHA-1";public static final Integer COUNTS =369;/*** @Description sha1方法* @param input 需要散列字符串* @param salt 鹽字符串* @return*/public static String show(String input, String salt) {return new SimpleHash(SHA1, input, salt,COUNTS).toString();}/*** @Description 隨機獲得salt字符串* @return*/public static String generateSalt(){SecureRandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();return randomNumberGenerator.nextBytes().toHex();}/*** @Description 生成密碼字符密文和salt密文* @param* @return*/public static Map<String,String> entryptPassword(String passwordPlain) {Map<String,String> map = new HashMap<>();String salt = generateSalt();String password =show(passwordPlain,salt);map.put("salt", salt);map.put("password", password);return map;}
}

2.6.全局異常處理器

@ControllerAdvice
public class BaseExceptionHandler {@ExceptionHandler(value = AuthorizationException.class)@ResponseBodypublic String error(HttpServletRequest request, HttpServletResponse response, AuthorizationException e){return "未授權!!!";}
}

2.7自定義Realm

public class MyRealm extends AuthorizingRealm {@AutowiredIUserService userService;@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {int userId = (int) principalCollection.getPrimaryPrincipal();User user = userService.findUserDetailById(userId);Set<String> roles = new HashSet<>();Set<String> permissions = new HashSet<>();user.getRoles().stream().forEach(role -> {roles.add(role.getCode());role.getPermissions().stream().forEach(permission -> {permissions.add(permission.getCode());});});SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();info.addRoles(roles);info.addStringPermissions(permissions);return info;}/*** 認證方法*  參數:傳遞的用戶名密碼*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//1.獲取登錄的用戶名密碼(token)UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String username = token.getUsername();//2.根據用戶名查詢數據庫//mybatis情景下:user對象中包含ID,name,pwd(匿名)User user = userService.findUserByName(username);if(user != null){SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getId(),user.getPassword(), ByteSource.Util.bytes(user.getSalt()),"myRealm");return info;}return null;}/*** @Description 自定義密碼比較器* @param* @return* bean標簽 init-method屬性*/@PostConstructpublic void initCredentialsMatcher() {//指定密碼算法HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(DigestsUtil.SHA1);//指定迭代次數hashedCredentialsMatcher.setHashIterations(DigestsUtil.COUNTS);//生效密碼比較器setCredentialsMatcher(hashedCredentialsMatcher);}
}

2.8shiro配置類

@Configuration
public class ShiroConfiguration {/*** 1.創建shiro自帶cookie對象*/@Beanpublic SimpleCookie sessionIdCookie(){SimpleCookie simpleCookie = new SimpleCookie();simpleCookie.setName("ShiroSession");return simpleCookie;}//2.創建realm@Beanpublic MyRealm getRealm(){return new MyRealm();}/*** 3.創建會話管理器*/@Beanpublic DefaultWebSessionManager sessionManager(){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionValidationSchedulerEnabled(false);sessionManager.setSessionIdCookieEnabled(true);sessionManager.setSessionIdCookie(sessionIdCookie());sessionManager.setGlobalSessionTimeout(3600000);return sessionManager;}//4.創建安全管理器@Beanpublic SecurityManager defaultWebSecurityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(getRealm());securityManager.setSessionManager(sessionManager());return securityManager;}/*** 5.保證實現了Shiro內部lifecycle函數的bean執行*/@Bean(name = "lifecycleBeanPostProcessor")public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** 6.開啟對shiro注解的支持*   AOP式方法級權限檢查*/@Bean@DependsOn("lifecycleBeanPostProcessor")public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}/*** 7.配合DefaultAdvisorAutoProxyCreator事項注解權限校驗*/@Beanpublic AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());return authorizationAttributeSourceAdvisor;}//8.配置shiro的過濾器工廠再web程序中,shiro進行權限控制全部是通過一組過濾器集合進行控制@Beanpublic ShiroFilterFactoryBean shiroFilter() {//1.創建過濾器工廠ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();//2.設置安全管理器filterFactory.setSecurityManager(defaultWebSecurityManager());//3.通用配置(跳轉登錄頁面,為授權跳轉的頁面)filterFactory.setLoginUrl("/autherror");//跳轉url地址//4.設置過濾器集合//key = 攔截的url地址//value = 過濾器類型Map<String,String> filterMap = new LinkedHashMap<>();//key:請求規則   value:過濾器名稱filterMap.put("/login","anon");//當前請求地址可以匿名訪問filterMap.put("/user/**","authc");//當前請求地址必須認證之后可以訪問//在過濾器工程內設置系統過濾器filterFactory.setFilterChainDefinitionMap(filterMap);return filterFactory;}}

三、案例演示

用戶密碼均是123456加密后保存至數據庫

3.1 登錄認證

成功登錄:
在這里插入圖片描述
失敗登錄:
在這里插入圖片描述

3.2 權限認證

由于剛剛登錄的信息有管理員和員工的身份,所以其所有功能都能使用。
有權限時:在這里插入圖片描述
無權限時:在這里插入圖片描述
無權限時會被全局異常處理器攔截,并作出響應的響應。


總結

通過對shrio的學習,更好的理解了安全認證以及鑒權授權的流程,大概了解了安全認證的機制,對我之后學習理解Springsecurity有更好的幫助。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/41781.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/41781.shtml
英文地址,請注明出處:http://en.pswp.cn/news/41781.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Git 刪除 GitHub倉庫的文件

新建文件夾 git bash here 在新建的文件夾里右鍵git bash here打開終端&#xff0c;并執行git init初始化倉庫 git clone <你的地址> 找到github上要刪除的倉庫地址&#xff0c;并復制&#xff0c;在終端里輸入git clone <你的地址> 要刪除文件的庫里右鍵git b…

BEV感知實時構建路口拓撲 覺非科技基于MapTR的優化與實踐

近期&#xff0c;覺非科技通過在車端與路端的大規模數據積累&#xff0c;基于MapTR&#xff08;Map TRansformer&#xff09;方法提出了創新與優化&#xff1a;①對車道信息的表達方式進行優化&#xff0c;并簡化了模型結構&#xff1b;②在MapTR的基礎上加入了地圖先驗信息&am…

歸并排序(C++ mpi 并行實現)

文章目錄 主要思路1. 串行歸并排序2. 進程的分發3. 對接收到的子數組進行排序4. 合并數組5.輸出排序后的數組6.進程分發部分的優化7.完整代碼 主要思路 我們首先實現串行的歸并排序&#xff1b;實現進程的分發&#xff1b;排序其中的每個子部分&#xff1b;進程的合并通信&…

Spring、Springboot、SpringCloud--包含的知識點大全

類型難度AOPspring-自定義AOP面向切面注解--統一切面處理-登陸信息采集快速入門SpringbootAOP實現切面處理請求Demo線程池通俗易懂的線程池底層原理&#xff0c;一文知所有數據結構數據結構-鏈表篇數據結構--數組篇數據結構之-concurrentHashMap源碼分析JVMJVM調優及各種問題處…

理解 Go 中的切片:append 操作的深入分析(篇2)

理解 Go 語言中 slice 的性質對于編程非常有益。下面&#xff0c;我將通過代碼示例來解釋切片在不同函數之間傳遞并執行 append 操作時的具體表現。 本篇為第 2 篇&#xff0c;當切片的容量 cap 不夠時 func main() {// slice1 當前長度為 3&#xff0c;容量大小也為 3slice1 :…

.netcore grpc的proto文件字段詳解

一、.proto文件字段概述 grpc的接口傳輸參數都是根據.proto文件約定的字段格式進行傳輸的grpc提供了多種類型字段&#xff1b;主要包括標量值類型&#xff08;基礎類型&#xff09;、日期時間、可為null類型、字節、列表、字典、Any類型&#xff08;任意類型&#xff09;、One…

前端筆試+面試分享

以下是個人線下面試遇到的真實的題&#xff0c;僅供參考和學習 1. css 選擇符有哪些&#xff1f;哪些屬性可以繼承&#xff1f;優先級算法加何計算&#xff1f; CSS選擇符有很多種&#xff0c;例如類型選擇器、類選擇器、ID選擇器、屬性選擇器、偽類選擇器、偽元素選擇器等。 …

【1day】復現海康威視綜合安防管理平臺artemis接口Spring boot heapdump內存泄露漏洞

目錄 一、漏洞描述 二、影響版本 三、資產測繪 四、漏洞復現 一、漏洞描述 HIKVISION iSecure Center綜合安防管理平臺是一套“集成化”、“智能化”的平臺,通過接入視頻監控、一卡通

Algorithem Review 5.2 圖論

網絡流 設源點為 s s s&#xff0c;匯點為 t t t&#xff0c;每條邊 e e e 的流量上限為 c ( e ) c(e) c(e)&#xff0c;流量為 f ( e ) f(e) f(e)。割 指對于某一頂點集合 P ? V P \subset V P?V&#xff0c;從 P P P 出發指向 P P P 外部的那些原圖中的邊的集合&a…

回歸預測 | MATLAB實現基于SSA-KELM-Adaboost麻雀算法優化核極限學習機結合AdaBoost多輸入單輸出回歸預測

回歸預測 | MATLAB實現基于SSA-KELM-Adaboost麻雀算法優化核極限學習機結合AdaBoost多輸入單輸出回歸預測 目錄 回歸預測 | MATLAB實現基于SSA-KELM-Adaboost麻雀算法優化核極限學習機結合AdaBoost多輸入單輸出回歸預測預測效果基本介紹模型描述程序設計參考資料 預測效果 基本…

SSH遠程連接MacOS catalina并進行終端顏色配置

一、開關SSH服務 在虛擬機上安裝了MacOS catalina&#xff0c;想要使用SSH遠程進行連接&#xff0c;但是使用“系統偏好設置”/“共享”/“遠程登錄”開關進行打開&#xff0c;卻一直是正在啟動“遠程登錄”&#xff1a; 難道是catalina有BUG&#xff1f;不過還是有方法的&…

第07天 Static關鍵字作用及用法

?作者簡介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;熱愛Java后端開發者&#xff0c;一個想要與大家共同進步的男人&#x1f609;&#x1f609; &#x1f34e;個人主頁&#xff1a;Leo的博客 &#x1f49e;當前專欄&#xff1a;每天一個知識點 ?特色專欄&#xff1a…

【前端|Javascript第5篇】全網最詳細的JS的內置對象文章!

前言 在當今數字時代&#xff0c;前端技術正日益成為塑造用戶體驗的關鍵。我們在開發中需要用到很多js的內置對象的一些屬性來幫助我們更快速的進行開發。或許你是剛踏入前端領域的小白&#xff0c;或者是希望深入了解內置對象的開發者&#xff0c;不論你的經驗如何&#xff0c…

使用Dockerfile制作RocketMq的Docker鏡像(任意版本)

使用dockerfile制作任意版本的docker鏡像 1、Dockerfile 創建文件rocketmq #FROM openjdk:8 FROM java8:1.0 #上面的基礎鏡像可以自己 docker pull LABEL "作者"=aaaaaENV ROCKETMQ_VERSION 5.1.3 # ENV LANG en_US.UTF-8ENV ROCKETMQ_HOME="/home/rocketm…

MATLAB中的代數環概念

在 Simulink 模型中&#xff0c;當存在信號環并且信號環中只存在直接饋通模塊時&#xff0c;將出現代數環。直接饋通表示 Simulink 需要模塊輸入信號的值來計算當前時間步的輸出。這種信號循環會在同一時間步中產生模塊輸出和輸入的循環依存關系。這會導致一個需要在每個時間步…

【【verilog典型電路設計之流水線結構】】

verilog典型電路設計之流水線結構 下圖是一個4位的乘法器結構&#xff0c;用verilog HDL 設計一個兩級流水線加法器樹4位乘法器 對于流水線結構 其實需要做的是在每級之間增加一個暫存的數據用來存儲 我們得到的東西 我們一般來說會通過在每一級之間插入D觸發器來保證數據的聯…

Oracle 數據庫備份

1、使用管理員賬號創建對應的directory目錄 登錄數據庫 sqlplus / as sysdba 創建directory create or replace directory dumpdir as F:\container; 2、給用戶賦予使用該目錄的權限 grant read,write on directory dumpdir to Scott; 查看創建的目錄位置 select * fro…

OpenCV-Python中的圖像處理-圖像特征

OpenCV-Python中的圖像處理-圖像特征 圖像特征Harris角點檢測亞像素級精度的角點檢測Shi-Tomasi角點檢測SIFT(Scale-Invariant Feature Transfrom)SURF(Speeded-Up Robust Features)FAST算法BRIEF(Binary Robust Independent Elementary Features)算法ORB (Oriented FAST and R…

JavaScript判空設默認值的幾種寫法

前端面試題庫 &#xff08;面試必備&#xff09; 推薦&#xff1a;★★★★★ 地址&#xff1a;前端面試題庫 實踐中需要給某個變量賦值時&#xff0c;若數據來源不可控&#xff0c;通常會給它設置一個默認值&#xff08;就像空對象模式一樣&#xff09;。JavaScri…

python編程中有哪些方便的調試方法

大家好&#xff0c;給大家分享一下一個有趣的事情&#xff0c;很多人還不知道這一點。下面詳細解釋一下。現在讓我們來看看&#xff01; 對于每個程序開發者來說&#xff0c;調試幾乎是必備技能。常用Pycharm編輯器里的方法有Print大法、log大法&#xff0c;但缺少類似Matlab的…