shiro 登錄攔截和用戶認證、資源授權


shiro 登錄攔截和用戶認證、資源授權

  • Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼和會話管理。

  • 三個核心組件:Subject, SecurityManager 和 Realms.

    1. Subject   Subject:即“當前操作用發戶”。但是,在Shiro中,Subject這一概念並不僅僅指人,也可以是第三方進程、后台帳戶(Daemon Account)或其他類似事物。它僅僅意味着“當前跟軟件交互的東西”。但考慮到大多數目的和用途,你可以把它認為是Shiro的“用戶”概念。Subject代表了當前用戶的安全操作,SecurityManager則管理所有用戶的安全操作。

    1. SecurityManager   SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內部組件實例,並通過它來提供安全管理的各種服務。

    1. Realm   Realm充當了Shiro與應用安全數據間的“橋梁”或者“連接器”。也就是說,當對用戶執行認證(登錄)和授權(訪問控制)驗證時,Shiro會從應用配置的Realm中查找用戶及其權限信息。   從這個意義上講,Realm實質上是一個安全相關的DAO:它封裝了數據源的連接細節,並在需要時將相關數據提供給Shiro。當配置Shiro時,你必須至少指定一個Realm,用於認證和(或)授權。配置多個Realm是可以的,但是至少需要一個。   Shiro內置了可以連接大量安全數據源(又名目錄)的Realm,如LDAP、關系數據庫(JDBC)、類似INI的文本配置資源以及屬性文件等。如果缺省的Realm不能滿足需求,你還可以插入代表自定義數據源的自己的Realm實現。

項目目錄結構

 

 

 

 

添加依賴

pom.xml

<dependencies>
       <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
           <version>1.16.10</version>
           <scope>provided</scope>
       </dependency>

   <!-- 導入web支持:SpringMVC開發支持,Servlet相關的程序 -->
   <!-- web支持,SpringMVC, Servlet支持等 -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
       <!-- 導入thymeleaf依賴 -->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-thymeleaf</artifactId>
       </dependency>
       <!-- shiro與spring整合依賴 -->
       <dependency>
           <groupId>org.apache.shiro</groupId>
           <artifactId>shiro-spring</artifactId>
           <version>1.4.0</version>
       </dependency>

       <!-- 導入mybatis相關的依賴 -->
       <dependency>
           <groupId>com.alibaba</groupId>
           <artifactId>druid</artifactId>
           <version>1.0.9</version>
       </dependency>
       <!-- mysql -->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>8.0.18</version>
       </dependency>
       <!-- SpringBoot的Mybatis啟動器 -->
       <dependency>
           <groupId>org.mybatis.spring.boot</groupId>
           <artifactId>mybatis-spring-boot-starter</artifactId>
           <version>1.1.1</version>
       </dependency>

       <!-- thymel對shiro的擴展坐標 -->
       <dependency>
           <groupId>com.github.theborakompanioni</groupId>
           <artifactId>thymeleaf-extras-shiro</artifactId>
           <version>2.0.0</version>
       </dependency>
   </dependencies>
   <!-- 修改參數 -->
   <properties>

       <!-- 修改thymeleaf的版本 -->
       <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
       <thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
   </properties>

<!--將xml文件放在src下,訪問xml文件資源-->
   <build>
       <resources>
           <resource>
               <directory>src/main/java</directory>
               <includes>
                   <include>**/*.xml</include>
               </includes>
           </resource>
       </resources>
   </build>

 

整合mybatis

application.properties

spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springbootshiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
spring.datasource.username=root
spring.datasource.password=12


#數據庫連接池的配置
spring.datasouce.type=com.alibaba.druid.pool.DruidDataSource

#mybatis別名掃描配置
mybatis.type-aliases-package=com.bxb.domain

dao層

User.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;


@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
   private Integer id;
   private String name;
   private String password;
   private String perms;
}

Mapper

Usermapper.java

import com.bxb.domain.User;
import org.apache.ibatis.annotations.Mapper;

//@Mapper
public interface UserMapper {

   User findUserByName(String name);

   User findUserById(Integer id);
}

UseMapper.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.bxb.Mapper.UserMapper">
   <select id="findUserByName" parameterType="string" resultType="user">
      select *
      from user
      where name=#{name}
   </select>

   <select id="findUserById" parameterType="integer" resultType="user">
      select *
      from user
      where id=#{id}
   </select>
</mapper>

Service

UserService.java

public interface UserService {
   User findByName(String name);
   User findById(Integer id);
}

UserServiceImpl

UserServiceImpl.java

@Service
public class UserServiceImpl implements UserService {

   @Autowired
   private UserMapper userMapper;
   @Override
   public User findByName(String name) {
       return userMapper.findUserByName(name);
  }

   @Override
   public User findById(Integer id) {
       return userMapper.findUserById(id);
  }
}

前端頁面

login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
   <meta charset="UTF-8">
   <title>登錄</title>
</head>
<body>
<h3>登錄</h3>
<h3 th:text="${msg}" style="color:red"></h3>
<form method="post" action="login">
  用戶名:<input type="text" name="name"/></br>
  密碼:<input type="password" name="password"/></br>
   <input type="submit" value="登錄"/>

</form>
</body>
</html>

test.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>
<h3 th:text="${name}"></h3>

<hr/>
<div th:if="${session.loginUser==null}">
   <a href="toLogin">登錄</a>
</div>
<div shiro:hasPermission="user:add">
用戶添加:<a href="add">添加</a>
</div>
<hr/>
<div shiro:hasPermission="user:update">
用戶修改:<a href="update">修改</a>
</div>
</body>
</html>

noAuth.html

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>未授權提示頁面</title>
</head>
<body>
你還沒有經過授權!!!
</body>
</html>

 

shiro配置文件

shiroConfig.java

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 securityManager){
       ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
       //關聯安全管理器
       shiroFilterFactoryBean.setSecurityManager(securityManager);
       /**
        * Shiro內置過濾器,可以實現權限相關的攔截器
        * 常用的過濾器:
        *     anon:無需認證(登錄)可以訪問
        *     authc:必須認證才能訪問
        *     user:如果使用rememberMe的功能才可以直接訪問
        *     perms:該資源必須得到資源權限才可以訪問
        *     role:該資源必須得到角色權限才可以訪問
        */

       Map<String, String> filterMap=new LinkedHashMap<String, String>();
//       filterMap.put("/add","authc");
//       filterMap.put("/update","authc");
       filterMap.put("/testThymeleaf","anon");
       filterMap.put("/login","anon");
       //授權過濾器
       //注意:當前授權攔截后,shiro會自動跳轉到未授權頁面
       filterMap.put("/add","perms[user:add]");
       filterMap.put("/update","perms[user:update]");
       filterMap.put("/*","authc");

       //修改調整的登錄界面
       shiroFilterFactoryBean.setLoginUrl("/toLogin");//攔截成功跳轉的登錄界面
       //設置未授權的提示頁面
       shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
       shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
       return shiroFilterFactoryBean;
  }

   /**
    * 創建DefaultWebSecuityManager
    *@Qualifier注解的用處:當一個接口有多個實現的時候,為了指名具體調用哪個類的實現
    */
       @Bean(name="securityManager")
       public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
           DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
           //關聯realm
           securityManager.setRealm(userRealm);
           return securityManager;
      }


   /**
    * 創建Realm
    */
   @Bean(name="userRealm")  //將方法返回的對象放入spring環境
   public UserRealm getRealm(){
       return new UserRealm();
  }

   /**
    * 配置ShiroDialect,用於thymeleaf和shiro標簽配合使用
    */
   @Bean
   public ShiroDialect getShiroDialect(){
       return new ShiroDialect();
  }
}

UserRealm.java

import com.bxb.Service.UserService;
import com.bxb.domain.User;
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.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

import java.awt.*;

import static java.awt.SystemColor.info;

/**
* 自定義Realm
*/
public class UserRealm extends AuthorizingRealm {
   /**
    * 執行授權邏輯
    * @param principalCollection
    * @return
    */
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       System.out.println("執行授權邏輯");
       //給資源進行授權
       SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

       //添加資源的授權字符串
       //info.addStringPermission("user:add");

       //到數據庫查詢當前登錄用戶的授權字符串
       //獲取當前登錄用戶
       Subject subject = SecurityUtils.getSubject();
       User user= (User) subject.getPrincipal();
       User dbuser=userService.findById(user.getId());
       info.addStringPermission(dbuser.getPerms());
//       info.addStringPermission(user.getPerms());
       return info;
  }

   /**
    * 執行認證邏輯
    * @param authenticationToken
    * @return
    * @throws AuthenticationException
    */

   @Autowired
   private UserService userService;
   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       System.out.println("執行認證邏輯");

       //假設數據庫的用戶名和密碼
//       String name="aaa";
//       String password="123";
       //編寫shiro判斷邏輯,判斷用戶名和密碼
       //1.判斷用戶名
       UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
       User user = userService.findByName(token.getUsername());
       Subject currentSubject = SecurityUtils.getSubject();
       Session session = currentSubject.getSession();
       session.setAttribute("loginUser",user);

       if(user==null){
           //用戶名不存在
           return null;//shiro底層會拋出UnKnowAccountException
      }
       //判斷密碼
       return new SimpleAuthenticationInfo(user,user.getPassword(),"");
  }
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM