99re热视频这里只精品,久久久天堂国产精品女人,国产av一区二区三区,久久久精品成人免费看片,99久久精品免费看国产一区二区三区

Apache Shiro安全框架詳解:認證、授權(quán)與加密功能

2024-12-27 14:11 更新

大家好,我是 V 哥。Apache Shiro 是一個強大且靈活的 Java 安全框架,專注于提供認證、授權(quán)、會話管理和加密功能。它常用于保護 Java 應(yīng)用的訪問控制,特別是在 Web 應(yīng)用中。相比于 Spring Security,Shiro 的設(shè)計更簡潔,適合輕量級應(yīng)用,并且在許多方面具有更好的易用性和擴展性,今天 V 哥就來聊聊 Shiro 安全框架。

Shiro 的核心概念

按照慣例,和 V 哥一起來了解一下 Shiro 的核心概念:

  1. Subject
    Subject 是 Shiro 框架中一個核心的接口,表示應(yīng)用中的“用戶”或“實體”,用于交互和存儲認證狀態(tài)。通常通過 SecurityUtils.getSubject() 獲取當前的 Subject。它代表了用戶的身份信息和權(quán)限數(shù)據(jù)。

  1. SecurityManager
    SecurityManager 是 Shiro 的核心控制器,負責管理所有的安全操作和認證。通過配置 SecurityManager,可以控制用戶的認證、授權(quán)、會話等管理。

  1. Realm
    Realm 是 Shiro 從數(shù)據(jù)源獲取用戶、角色和權(quán)限信息的途徑。通過實現(xiàn)自定義的 Realm,可以將 Shiro 與數(shù)據(jù)庫、LDAP、文件等數(shù)據(jù)源整合。Shiro 會把用戶的認證和授權(quán)數(shù)據(jù)從 Realm 中獲取。

  1. Session
    Shiro 自帶會話管理,不依賴于 Servlet 容器提供的會話。即使在非 Web 環(huán)境下,也可以使用 Shiro 的會話管理。Shiro 的會話管理提供了更細致的控制,比如會話超時、存儲和共享等功能。

  1. Authentication(認證)
    認證是指驗證用戶身份的過程。Shiro 提供了簡單的 API 來實現(xiàn)認證過程,比如 subject.login(token)。在實際應(yīng)用中,通常通過用戶名和密碼的組合進行認證,但 Shiro 也支持其他方式(如 OAuth2、JWT 等)。

  1. Authorization(授權(quán))
    授權(quán)是指驗證用戶是否具備某些權(quán)限或角色的過程。Shiro 支持基于角色和基于權(quán)限的授權(quán),允許更精細的權(quán)限控制。通過 subject.hasRolesubject.isPermitted 方法,開發(fā)者可以檢查用戶的角色和權(quán)限。

  1. Cryptography(加密)
    Shiro 內(nèi)置了加密功能,提供對密碼和敏感信息的加密和解密支持。它支持多種加密算法,并且在密碼存儲時支持散列和鹽值。

Shiro 的主要功能和優(yōu)勢

V 哥總結(jié)幾點Shiro 的主要功能和優(yōu)勢,這個在面試時吹牛逼用得到。

  1. 易于集成
    Shiro 的 API 設(shè)計簡單,易于集成到各種 Java 應(yīng)用中。開發(fā)者可以基于 Shiro 提供的默認實現(xiàn)快速搭建一個基本的安全架構(gòu),也可以根據(jù)需要自定義各種功能。

  1. 獨立的會話管理
    與基于 Web 容器的會話管理不同,Shiro 提供了跨環(huán)境的會話管理,可以應(yīng)用于 Web 和非 Web 的環(huán)境,增加了應(yīng)用的靈活性。

  1. 權(quán)限控制簡單而靈活
    Shiro 的權(quán)限管理可以通過配置文件、注解或代碼實現(xiàn),提供了細粒度的訪問控制。通過權(quán)限和角色的組合,開發(fā)者可以非常靈活地控制訪問權(quán)限。

  1. 支持多種數(shù)據(jù)源
    Shiro 可以從多種數(shù)據(jù)源(如數(shù)據(jù)庫、LDAP、文件等)獲取用戶和權(quán)限信息,方便與各種現(xiàn)有系統(tǒng)整合。

  1. 支持 Web 和非 Web 環(huán)境
    Shiro 不僅可以在 Web 應(yīng)用中使用,也支持在桌面應(yīng)用或微服務(wù)等環(huán)境中使用。

Shiro 的基本使用示例

光講概念不是 V 哥風格,接下來,通過一個典型的 Shiro 應(yīng)用來了解一下如何使用,包含配置 SecurityManager、配置 Realm、進行認證和授權(quán)等步驟。

  1. 配置 Shiro 環(huán)境 可以通過 shiro.ini 文件配置 Shiro,也可以通過代碼進行配置。

   [main]
   # 配置 SecurityManager
   securityManager = org.apache.shiro.mgt.DefaultSecurityManager


   # 配置 Realm
   myRealm = com.wg.MyCustomRealm
   securityManager.realms = $myRealm

  1. 創(chuàng)建自定義 Realm

自定義 Realm 通過繼承 AuthorizingRealm 并實現(xiàn) doGetAuthenticationInfodoGetAuthorizationInfo 方法來提供用戶和權(quán)限數(shù)據(jù)。

   public class MyCustomRealm extends AuthorizingRealm {
       @Override
       protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
           // 獲取用戶名和密碼等信息,查詢數(shù)據(jù)庫進行認證
           return new SimpleAuthenticationInfo(username, password, getName());
       }


       @Override
       protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
           // 獲取用戶角色和權(quán)限信息
           SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
           info.addRole("admin");
           info.addStringPermission("user:read");
           return info;
       }
   }

  1. 使用 Shiro 進行認證和授權(quán)

   Subject currentUser = SecurityUtils.getSubject();
   if (!currentUser.isAuthenticated()) {
       UsernamePasswordToken token = new UsernamePasswordToken("username", "password");
       try {
           currentUser.login(token);
           System.out.println("認證成功");
       } catch (AuthenticationException ae) {
           System.out.println("認證失敗");
       }
   }


   // 檢查權(quán)限
   if (currentUser.hasRole("admin")) {
       //用輸出模擬一下哈
       System.out.println("用戶擁有 admin 角色");
   }
   if (currentUser.isPermitted("user:read")) {
       //用輸出模擬一下哈
       System.out.println("用戶具有 user:read 權(quán)限");
   }

通過這個簡單的案例學習,咱們可以了解 Shiro 的基本使用,但這不是全部,聽V哥繼續(xù)慢慢道來。

場景案例

這點很重要,強調(diào)一下哈,Shiro 適合需要簡潔易用、安全控制要求靈活的 Java 應(yīng)用,如中小型 Web 應(yīng)用、桌面應(yīng)用、分布式微服務(wù)等。對于大型企業(yè)應(yīng)用或需要集成多種認證方式(如 OAuth2、JWT 等)的項目,Spring Security 可能會更合適。

要在微服務(wù)架構(gòu)中實現(xiàn)基于 Apache Shiro 的安全認證和授權(quán),比如一個訂單管理系統(tǒng)為例。這個系統(tǒng)包含兩個主要服務(wù):

  1. 用戶服務(wù):負責用戶的注冊、登錄、認證等操作。
  2. 訂單服務(wù):允許用戶創(chuàng)建、查看、刪除訂單,并限制訪問權(quán)限。

咱們來看一下,這個應(yīng)該怎么設(shè)計呢?

微服務(wù)案例設(shè)計

在這個場景中,我們需要以下幾項核心功能:

  1. 用戶認證:用戶通過用戶名和密碼登錄。
  2. 權(quán)限控制:僅管理員能刪除訂單,普通用戶只能查看和創(chuàng)建訂單。
  3. Token機制:使用 JWT Token(JSON Web Token)來管理用戶的登錄狀態(tài),實現(xiàn)無狀態(tài)認證,使得在分布式環(huán)境下不依賴于單一會話。
  4. 跨服務(wù)認證:訂單服務(wù)在接收到請求時,檢查并驗證用戶的身份和權(quán)限。

架構(gòu)和技術(shù)選型

  • Spring Boot:用于快速搭建微服務(wù)。
  • Shiro:實現(xiàn)認證、授權(quán)。
  • JWT:生成和驗證 Token,保持無狀態(tài)認證。
  • Spring Data JPA:訪問數(shù)據(jù)庫存儲用戶和訂單數(shù)據(jù)。

系統(tǒng)結(jié)構(gòu)

+------------------+      +---------------------+
|   用戶服務(wù)        |      |     訂單服務(wù)        |
|                  |      |                     |
| 用戶注冊、登錄    |      |   查看、創(chuàng)建、刪除訂單|
+------------------+      +---------------------+
            |                    |
            |----用戶 Token ------|

步驟:實現(xiàn)微服務(wù)中的認證和授權(quán)

1. 引入必要的依賴

pom.xml 文件中,添加 Shiro、JWT 和 Spring Data JPA 等依賴:

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.8.0</version>
</dependency>


<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

2. 配置 Shiro 與 JWT 過濾器

使用 Shiro 的自定義 JWT 過濾器實現(xiàn)無狀態(tài)認證,通過 Token 驗證用戶。

public class JwtFilter extends BasicHttpAuthenticationFilter {


    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader("Authorization");


        if (StringUtils.isBlank(token)) {
            return false;
        }


        try {
            // 解析 JWT token
            JwtToken jwtToken = new JwtToken(token);
            getSubject(request, response).login(jwtToken);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

3. 實現(xiàn)自定義 Realm

自定義 Realm,從數(shù)據(jù)庫獲取用戶和角色信息,并使用 JWT Token 進行無狀態(tài)認證。

public class JwtRealm extends AuthorizingRealm {


    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }


    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String jwtToken = (String) token.getPrincipal();


        // 驗證 Token
        String username = JwtUtil.getUsernameFromToken(jwtToken);
        if (username == null) {
            throw new AuthenticationException("Token 無效");
        }


        // 查詢用戶
        User user = userService.findByUsername(username);
        if (user == null) {
            throw new AuthenticationException("用戶不存在");
        }


        return new SimpleAuthenticationInfo(jwtToken, jwtToken, getName());
    }


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = JwtUtil.getUsernameFromToken(principals.toString());


        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user = userService.findByUsername(username);


        // 添加角色和權(quán)限
        authorizationInfo.addRole(user.getRole());
        authorizationInfo.addStringPermission(user.getPermission());


        return authorizationInfo;
    }
}

4. 創(chuàng)建 JWT 工具類

編寫一個工具類,用于生成和解析 JWT Token。

public class JwtUtil {


    //這里替換一下你自己的secret_key
    private static final String SECRET_KEY = "這里打碼了"; 


    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1 hour
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }


    public static String getUsernameFromToken(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }


    public static boolean isTokenExpired(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
        return claims.getExpiration().before(new Date());
    }
}

5. 編寫用戶服務(wù)和訂單服務(wù)接口

用戶服務(wù)接口

用戶服務(wù)提供注冊和登錄 API。

@RestController
@RequestMapping("/user")
public class UserController {


    @PostMapping("/register")
    public ResponseEntity<?> register(@RequestBody User user) {
        userService.save(user);
        return ResponseEntity.ok("用戶注冊成功");
    }


    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody User user) {
        User dbUser = userService.findByUsername(user.getUsername());
        if (dbUser != null && dbUser.getPassword().equals(user.getPassword())) {
            String token = JwtUtil.generateToken(user.getUsername());
            return ResponseEntity.ok(token);
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("登錄失敗");
    }
}

訂單服務(wù)接口

訂單服務(wù)在操作訂單時會驗證用戶的角色和權(quán)限。

@RestController
@RequestMapping("/order")
public class OrderController {


    @GetMapping("/{orderId}")
    public ResponseEntity<?> getOrder(@PathVariable Long orderId) {
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.isPermitted("order:read")) {
            // 查詢訂單
            return ResponseEntity.ok("訂單詳情");
        }
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body("無權(quán)限查看訂單");
    }


    @DeleteMapping("/{orderId}")
    public ResponseEntity<?> deleteOrder(@PathVariable Long orderId) {
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.hasRole("admin")) {
            // 刪除訂單
            return ResponseEntity.ok("訂單已刪除");
        }
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body("無權(quán)限刪除訂單");
    }
}

最后

這個案例中咱們通過如何使用 Shiro、JWT 和 Spring Boot 來構(gòu)建一個無狀態(tài)的微服務(wù)認證授權(quán)機制。通過 Shiro 實現(xiàn)用戶認證和權(quán)限控制,使用 JWT 實現(xiàn)無狀態(tài) Token 驗證。在輕量級的分布式微服務(wù)應(yīng)用中,是不是使用 Shiro 感覺更加清爽呢,歡迎評論區(qū)一起討論,關(guān)注威哥愛編程,愛上Java,一輩子。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號