入門shiro(感覺成功了)首先感謝狂神,然后我就一本正經的復制代碼了
項目結構
運行效果
數據庫
<dependencies> <!-- thymeleaf-shiro整合包 --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <!--快速生成pojo的方法有關的lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency> <!-- 引入 myBatis,這是 MyBatis官方提供的適配 Spring Boot 的,而不是Spring Boot自己的--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- Subject 用戶, SecurityManager 管理所有用戶, Realm 連接數據,需要自定義 --> <!--shiro整合spring的包--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--thymeleaf模板--> <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.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
ShiroConfig.class
@Configuration public class ShiroConfig { //ShiroFilterFactoryBean 第三步 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //設置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); /* 添加shiro的內置過濾器 anon:無須認證就可以訪問 authc:必須認證了才可以訪問 perms:擁有對某個資源的權限才能訪問 role:擁有某個角色才可以訪問 */ Map<String, String> filterMap = new LinkedHashMap(); // filterMap.put("/user/add","authc"); // filterMap.put("/user/update","authc"); filterMap.put("/user/add","perms[user:add]"); filterMap.put("/user/update","perms[user:update]"); filterMap.put("/user/*","authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); //設置跳轉到登錄頁面 shiroFilterFactoryBean.setLoginUrl("/toLogin"); //設置到未授權頁面 shiroFilterFactoryBean.setUnauthorizedUrl("/noauth"); return shiroFilterFactoryBean; } //DefaultWebSecurityManager 第二步 @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); //關聯realm securityManager.setRealm(userRealm); return securityManager; } //創建realm 域對象,需要自定義 第一步 @Bean(name = "userRealm") public UserRealm getUserRealm(){ return new UserRealm(); } //shiro 整合thymeleaf @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } }
UserRealm.class
public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override //授權 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("-----授權了-----AuthorizationInfo"); SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(); // info.addStringPermission("user:add"); //從數據庫查權限 Subject subject = SecurityUtils.getSubject(); User currentUser = (User) subject.getPrincipal();//其實就是拿認證成功的時候的那個user info.addStringPermission(currentUser.getPerms()); return info; } @Override //認證 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("-----認證了-----AuthenticationInfo"); UsernamePasswordToken userToken = (UsernamePasswordToken) token; //用戶名,密碼去數據庫取 User user = userService.queryUserByUsername(userToken.getUsername()); if (user==null){ //沒有這個人 return null; //其實就是拋出UnknownAccountException異常 } //之后密碼認證,shiro 它自己會做 SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(user,user.getPassword(),""); Subject currentSubject = SecurityUtils.getSubject(); Session session = currentSubject.getSession(); session.setAttribute("loginUser",user); return info; } }
MyController.class
@Controller public class MyController { @RequestMapping({"/","/index"}) public String toIndex(Model model){ model.addAttribute("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); 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 "沒經授權無法進入"; } //退出 @RequestMapping("/logout") public String logout(){ Subject currentUser = SecurityUtils.getSubject(); currentUser.logout(); System.out.println("退出了"); return "login"; } }
User.class
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String username; private String password; private String perms; }
UserMapper.class
@Mapper @Repository public interface UserMapper { public User queryUserByUsername(String username); }
UserService.class
public interface UserService { public User queryUserByUsername(String username); }
UserServiceImpl.class
@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User queryUserByUsername(String username) { return userMapper.queryUserByUsername(username); } }
UserMapper.xml
<?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.kuang.mapper.UserMapper"> <select id="queryUserByUsername" parameterType="String" resultType="User"> select * from user where username=#{username} </select> </mapper>
application.properties
mybatis.type-aliases-package=com.kuang.pojo
mybatis.mapper-locations=classpath:mapper/*.xml
application.yml
spring: datasource: username: root password: root #?serverTimezone=UTC解決時區的報錯 url: jdbc:mysql://localhost:3306/shiro?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 driver-class-name: com.mysql.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: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
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>shiro</title> </head> <body> <h1>首頁</h1> <div th:if="${session.loginUser==null}"> <a th:href="@{/toLogin}">登錄</a> </div> <p th:text="${msg}"></p> <hr/> <div shiro:hasPermission="user:add"> <a th:href="@{/user/add}">add</a> </div> <div shiro:hasPermission="user:update"> <a th:href="@{/user/update}">update</a> </div> <div th:if="${session.loginUser}"> <p><a th:href="@{/logout}">退出</a></p> </div> </body> </html>
login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>shiro登錄</title> </head> <body> <div> <p th:text="${msg}" style="color: red"></p> <form method="get" th:action="@{/login}"> <p>用戶名:<input type="text" name="username"></p> <p>密 碼:<input type="text" name="password"></p> <p><input type="submit" value="登錄"></p> </form> </div> </body> </html>
add.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>增加</title> </head> <body> <h2>add</h2> </body> </html>
update.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>更新</title> </head> <body> <h2>update</h2> </body> </html>
總結一下:首先搭建好環境是關鍵:springboot--》MVC--》mybatis,然后進行shiro的過濾,認證,授權。。。
主要理解好
ShiroConfig
ShiroFilterFactoryBean
setFilterChainDefinitionMap()
DefaultWebSecurityManager
自定義域 UserRealm 繼承 AuthorizingRealm
AuthorizationInfo SimpleAuthenticationInfo
AuthenticationInfo SimpleAuthorizationInfo
UsernamePasswordToken
SecurityUtils
getSession()
getSubject()
getPrincipal()
AuthenticationToken
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。