Springboot-Shiro基本使用詳情介紹
Apache Shiro官網:https://shiro.apache.org/spring-boot.html.
一、依據官網快速搭建Quickstart
1.1 配置pom.xml依賴
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.7.1</version> </dependency> <!-- configure logging--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.21</version> </dependency> <!--調用日志框架--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
1.2配置log4j.properties
log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n # General Apache libraries log4j.logger.org.apache=WARN # Spring log4j.logger.org.springframework=WARN # Default Shiro logging log4j.logger.org.apache.shiro=INFO # Disable verbose logging log4j.logger.org.apache.shiro.util.ThreadContext=WARN log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
1.3 配置shiro.ini
[users] # user 'root' with password 'secret' and the 'admin' role root = secret, admin # user 'guest' with the password 'guest' and the 'guest' role guest = guest, guest # user 'presidentskroob' with password '12345' ("That's the same combination on # my luggage!!!" ;)), and role 'president' presidentskroob = 12345, president # user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz' darkhelmet = ludicrousspeed, darklord, schwartz # user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz' lonestarr = vespa, goodguy, schwartz # ----------------------------------------------------------------------------- # Roles with assigned permissions # # Each line conforms to the format defined in the # org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc # ----------------------------------------------------------------------------- [roles] # 'admin' role has all permissions, indicated by the wildcard '*' admin = * # The 'schwartz' role can do anything (*) with any lightsaber: schwartz = lightsaber:* # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with # license plate 'eagle5' (instance specific id) goodguy = winnebago:drive:eagle5
1.4啟動類
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Quickstart { private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class); public static void main(String[] args) { //使用shiro.ini文件在類路徑的根目錄 // (file:和url:前綴分別從文件和url加載): Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); //獲取當前的用戶對象Subject Subject currentUser = SecurityUtils.getSubject(); //通過當前用戶拿到session Session session = currentUser.getSession(); session.setAttribute("someKey", "aValue"); String value = (String) session.getAttribute("someKey"); if (value.equals("aValue")) { // log.info("Retrieved the correct value! [" + value + "]"); log.info("Subject=>session [" + value + "]"); } //判斷當前的用戶是否被認證 if (!currentUser.isAuthenticated()) { //Token :令牌,沒有獲取,隨機 UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); token.setRememberMe(true);//記住我 try { currentUser.login(token);//執行登錄操作~ } catch (UnknownAccountException uae) {//用戶名不存在 log.info("There is no user with username of " + token.getPrincipal()); } catch (IncorrectCredentialsException ice) {//密碼不對 log.info("Password for account " + token.getPrincipal() + " was incorrect!"); } catch (LockedAccountException lae) {//用戶被鎖定的 log.info("The account for username " + token.getPrincipal() + " is locked. " + "Please contact your administrator to unlock it."); } // ... catch more exceptions here (maybe custom ones specific to your application? catch (AuthenticationException ae) {//認證異常 //unexpected condition? error? } } //say who they are: //print their identifying principal (in this case, a username): log.info("User [" + currentUser.getPrincipal() + "] logged in successfully."); //test a role: if (currentUser.hasRole("schwartz")) { log.info("May the Schwartz be with you!"); } else { log.info("Hello, mere mortal."); } //粗粒度 //test a typed permission (not instance-level) if (currentUser.isPermitted("lightsaber:wield")) { log.info("You may use a lightsaber ring. Use it wisely."); } else { log.info("Sorry, lightsaber rings are for schwartz masters only."); } //細粒度 //a (very powerful) Instance Level permission: if (currentUser.isPermitted("winnebago:drive:eagle5")) { log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " + "Here are the keys - have fun!"); } else { log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!"); } //all done - log out! currentUser.logout(); System.exit(0); } }
二、springboot結合shiro使用
2.1準備數據庫
pom.xml添加依賴:
<dependencies> <!-- Subject 用戶 SecurityManager 管理所有用戶 Realm 連接數據 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.7.1</version> </dependency> <!-- configure logging--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.21</version> </dependency> <!--調用日志框架--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <!--連接數據--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <!--shiro整合spring的包--> <!--https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-java8time</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> </dependencies>
2.2配置yaml
spring: datasource: username: root password: 123456 #假如時區報錯瞭就增減一個時區的配置就ok瞭:servletTimezone=UTC url: jdbc:mysql://localhost:3306/security?servletTimezone=UTC&useUnicode=true&characterEncodeing=utf-8 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource #Spring Boot 默認是不註入這些屬性值的,需要自己綁定 #druid 數據源專有配置 initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true #配置監控統計攔截的filters,stat:監控日志,log4j:日志記錄,wall,預防sql註入 #如果允許時報錯 java.lang.ClassNotFoundException: org.apache.log4j.Priority #則導入log4j 依賴即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: durid.stat.mergeSql=true;druid.stat.slowSqlMillis=500 mybatis: mapper-locations: classpath:mapper/*.xml
使用thymeleaf寫幾個頁面:
index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"> <head> <meta charset="UTF-8"> <title>首頁</title> </head> <body> <h1>首頁</h1> <p>[[${msg}]]</p> <div th:if="session.LoginUser==null"><a th:href="@{toLogin}" rel="external nofollow" >登錄</a></div> <hr> <div shiro:hasPermission="user:add"> <a th:href="@{/user/add}" rel="external nofollow" >add.html</a></div> <div shiro:hasPermission="user:update"> <a th:href="@{/user/update}" rel="external nofollow" >update.html</a> </div> </body> </html>
login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登錄</h1> <hr> <p th:text="${msg}" style="color:red"></p> <form th:action="@{/login}"> <p>用戶名<input type="text" name="username"></p> <p>密碼<input type="text" name="password"></p> <p><input type="submit" value="登錄"></p> </form> </body> </html>
add.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>add</h4> </body> </html>
update.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>update</h4> </body> </html>
三、實體類
package com.jsxl.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private String password; private String auth; }
3.1UserMapper即UserMapper.xml
package com.jsxl.mapper; import com.jsxl.pojo.User; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository; @Repository @Mapper public interface UserMapper { public User queryUserByName(String name); }
<?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="com.jsxl.mapper.UserMapper" > <select id="queryUserByName" parameterType="String" resultType="com.jsxl.pojo.User"> select * from security.user where name=#{name} </select> </mapper>
UserController(簡單使用這裡直接調用Mapper):
package com.jsxl.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController { @RequestMapping({"/","/index"}) public String toIndex(ModelMap map){ map.put("msg","hello shiro"); return "index"; } @RequestMapping("user/add") public String add(){ return "user/add"; } @RequestMapping("user/update") public String update(){ return "user/update"; } @RequestMapping("/toLogin") public String toLogin(){ return "login"; } @RequestMapping("/login") public String login(String username, String password, Model model){ //獲取當前用戶 Subject subject = SecurityUtils.getSubject(); //封裝用戶的登錄數據 UsernamePasswordToken token = new UsernamePasswordToken(username, password); //這邊用瞭會存在整個的類裡面 try{ subject.login(token);//執行登錄的方法,如果沒有異常就說明ok瞭 return "index"; }catch(UnknownAccountException e){//用戶名不存在 model.addAttribute("msg","用戶名不存在"); return "login"; }catch(IncorrectCredentialsException e){//密碼不對 model.addAttribute("msg","密碼錯誤"); return "login"; } } @RequestMapping("/noauth") @ResponseBody public String unauthorized(){ return "未經授權無法訪問此頁面"; } }
四、shiro的配置類
package com.jsxl.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { //ShiroFilterFactoryBean @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //設置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); //添加shiro內置過濾器 /* anon :無需認證就可以訪問 autho:必須認證瞭才能訪問 user:必須擁有 記住我 功能才能用 perms:擁有對某個資源的權限才能訪問 role: 擁有某個角色權限才能訪問 */ //設置一個過濾器鏈 點擊源碼看需要什麼參數,由於是鏈表用LinkedHashMap 攔截 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); //授權 正常情況下 沒有授權會跳到未授權的頁面 filterChainDefinitionMap.put("/user/add","perms[user:add]"); filterChainDefinitionMap.put("/user/update","perms[user:update]"); // filterChainDefinitionMap.put("/user/add","authc"); // filterChainDefinitionMap.put("/user/update","authc"); filterChainDefinitionMap.put("/user/*","authc"); bean.setFilterChainDefinitionMap(filterChainDefinitionMap); //設置登錄請求 bean.setLoginUrl("/toLogin"); //未授權頁面 bean.setUnauthorizedUrl("/noauth"); return bean; } //DefaultWebSecurityManager 2 @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //關聯UserRealm securityManager.setRealm(userRealm); return securityManager; } //創建realm 對象 ,需要自定義類 1 @Bean(name = "userRealm")//正常情況下我們的方法名就是他 public UserRealm userRealm(){ return new UserRealm(); } @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } }
package com.jsxl.config; import com.jsxl.mapper.UserMapper; import com.jsxl.pojo.User; import com.jsxl.service.UserServiceImpl; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.session.Session; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; //自定義的UserRealm public class UserRealm extends AuthorizingRealm { @Autowired UserMapper userMapper; @Override//授權 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("執行瞭=>授權doGrtAuthorizationInfo"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // info.addStringPermission("user:add"); //拿到當前登錄的這個對象 Subject subject = SecurityUtils.getSubject(); User currentUser = (User)subject.getPrincipal();//拿到user對象 //設置當前登錄的用戶的權限 info.addStringPermission(currentUser.getAuth()); return info;//授權不能return null } @Override//認證 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("執行瞭=>認證doGrtAuthorizationInfo"); UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;//獲取信息 全局關系 User user = userMapper.queryUserByName(userToken.getUsername()); Subject currentSubject = SecurityUtils.getSubject(); Session session = currentSubject.getSession(); session.setAttribute("LoginUser",user); if(user==null){ return null;//拋出異常 UnknownAccountException } //密碼驗證 shiro做 有可能會泄露 加密瞭 return new SimpleAuthenticationInfo(user,user.getPassword(),""); } }
五、啟動類
package com.jsxl; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ShiroSpringbootApplication { public static void main(String[] args) { SpringApplication.run(ShiroSpringbootApplication.class, args); } }
測試:
root用戶
test用戶
5.1SecurityUtils. getSubject()
SecurityUtils. getSubject()
,可以獲得當前正在執行的Subject
. 一個Subject
就是一個應用程序的用戶的安全。實際上稱它為“User”,但太多的應用程序擁有已經擁有自己的 User 類/框架的現有 API,我們不想與它們發生沖突。此外,在安全領域,該術語Subject實際上是公認的術語。
getSubject()
獨立應用程序中的調用可能會Subject在特定於應用程序的位置返回基於用戶數據的 ,並且在服務器環境(例如 Web 應用程序)中,它Subject
根據與當前線程或傳入請求關聯的用戶數據獲取。
Session session = currentUser.getSession(); session.setAttribute( "someKey", "aValue" );
這Session
是一個特定於 Shiro 的實例,它提供瞭您習慣於使用常規 HttpSessions
的大部分內容,但還有一些額外的好處和一個很大的區別:它不需要 HTTP 環境!
到此這篇關於Springboot-Shiro基本使用詳情介紹的文章就介紹到這瞭,更多相關Springboot-Shiro使用 內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java shiro安全框架使用介紹
- 詳解Java springboot 整合Shiro框架
- SpringBoot 整合 Shiro 密碼登錄的實現代碼
- SpringBoot整合Shiro實現權限控制的代碼實現
- 基於SpringBoot2的Shiro最簡配置操作(兩個文件)