SpringBootがShiroを統合して権限制御を実装する方法

PHPz
リリース: 2023-05-16 16:55:40
転載
937 人が閲覧しました

1. SpringBoot は、Shiro を統合します。

Apache Tora は、認証、認可、パスワード、およびセッション管理を実行する、強力で使いやすい Java セキュリティ フレームワークです。

1.1. hiro の概要

Shiro には、Subject、SecurityManager、Realms というコアコンポーネントがあります。

  • Subject: 「現在のユーザー」に相当します。操作" "このユーザーは必ずしも特定の人物である必要はなく、クローラー、スクリプトなど、現在のプログラムと対話するあらゆるものを示す抽象的な概念です。すべてのサブジェクトは SecurityManager にバインドされており、サブジェクトとのすべての対話は SecurityManager に委任されます。サブジェクトはファサードとして考えることができ、SecurityManager が実際の実行者です。

  • SecurityManager: これは hiro フレームワークのコアです。すべてのセキュリティ関連の操作はこれと対話します。すべてのサブジェクトを管理します。

  • レルム:Shiro とアプリケーションのセキュリティ データ間の「ブリッジ」として機能します。ユーザーの認証 (ログイン) と認可 (アクセス制御) の検証を実行する際、SecurityManager は対応する情報を取得する必要があります。ユーザーの ID を比較して、ユーザーの ID が正当であるかどうかを判断します。また、ユーザーが操作を実行できるかどうかを確認するために、ユーザーの対応するロール/権限を Realm から取得する必要もあります。

1.2. コードの具体的な実装

1.2.1. Maven 設定

 <!--shiro-->
 <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.7.1</version>
        </dependency>
         <!--shiro整合thymeleaf-->
         <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
 <!--shiro缓存-->
  <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.7.1</version>
        </dependency>
ログイン後にコピー

hiro はデフォルトで jsp とともに使用されます。 thymeleaf を統合します thymeleaf を統合するために hiro にインポートする必要があるすべての jar パッケージ

1.2.2. 統合のために実装する必要があるクラス

  • 一般的に言えば、統合のみ2 つのクラスを完了する必要があります。それを実装するだけです。

  • 1 つは、ShiroConfig で、もう 1 つは CustomerRealmです。

  • シロ キャッシュを追加する必要がある場合、それは次のとおりです。組み込みキャッシュではなく Redis キャッシュです。他の 2 つのクラスを記述する必要があります。

  • 1 つは RedisCache で、もう 1 つは RedisCacheManager

# 1.2.3. プロジェクトの構造

SpringBootがShiroを統合して権限制御を実装する方法

1.2.4. TaroConfig の実装

#shiro を使用しないキャッシュ

package com.yuwen.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.yuwen.shiro.cache.RedisCacheManager;
import com.yuwen.shiro.realm.CustomerRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.Realm;
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.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {

    //让页面shiro标签生效
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

    //1、创建shiroFilter   负责拦截所有请求
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理
        factoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置系统的受限资源
        //配置系统公共资源 全部都能访问的设置anon
        Map<String,String> map = new HashMap<>();
        map.put("/main","authc");//请求这个资源需要认证和授权 authc表示需要认证后才能访问
        map.put("/admin","roles[admin]"); //表示admin角色才能访问 roles[]表示需要什么角色才能访问
        map.put("/manage","perms[user:*:*]"); //表示需要user:*:*权限才能访问 perms[]表示需要什么权限才能访问
        //访问需要认证的页面如果未登录会跳转到/login路由进行登陆
        factoryBean.setLoginUrl("/login");
        //访问未授权页面会自动跳转到/unAuth路由
        factoryBean.setUnauthorizedUrl("/unAuth");
        factoryBean.setFilterChainDefinitionMap(map);
        return factoryBean;
    }
    //2、创建安全管理器
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("getRealm") Realm realm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //给安全管理器设置
        securityManager.setRealm(realm);
        return securityManager;
    }
    //3、创建自定义的realm
    @Bean
    public Realm getRealm(){
        CustomerRealm customerRealm = new CustomerRealm();
        //修改凭证校验匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法为md5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //设置散列次数
        credentialsMatcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(credentialsMatcher);
        return customerRealm;
    }
}
ログイン後にコピー

一般的に安全ではないため、データベースにプレーン テキストのパスワードを設定します。ここでパスワードを設定します。MD5 暗号化では、暗号化方法は次のとおりです: パスワード = パスワード ソルト ハッシュ時間、その後 MD5 暗号化。したがって、ここでカスタム レルムを作成するときは、マッチャーを設定する必要があります。ログイン時にパスワードが正常に一致することを確認します。

1.2.5、CustomerRealm

package com.yuwen.shiro.realm;

import com.yuwen.pojo.User;
import com.yuwen.pojo.vo.ViewPerms;
import com.yuwen.pojo.vo.ViewRole;
import com.yuwen.service.UserService;
import com.yuwen.shiro.salt.MyByteSource;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.util.List;

//自定义realm
public class CustomerRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;
 //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取身份信息
        String primaryPrincipal = (String)principalCollection.getPrimaryPrincipal();
        //根据主身份信息获取角色 和 权限信息
        List<ViewRole> roles = userService.findRolesByUsername(primaryPrincipal);
        if (!CollectionUtils.isEmpty(roles)){
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            roles.forEach(viewRole -> {
                simpleAuthorizationInfo.addRole(viewRole.getName());
                //权限信息
                List<ViewPerms> perms = userService.findPermsByRoleId(viewRole.getName());
                if (!CollectionUtils.isEmpty(perms)){
                    perms.forEach(viewPerms -> {
                        simpleAuthorizationInfo.addStringPermission(viewPerms.getPName());
                    });
                }
            });
            return simpleAuthorizationInfo;
        }
        return null;
    }
    
 //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取登入的身份信息
        String principal = (String) authenticationToken.getPrincipal();
        User user = userService.findByUsername(principal);
        if (!ObjectUtils.isEmpty(user)){
            //ByteSource.Util.bytes(user.getSalt()) 通过这个工具将盐传入
            //如果身份认证验证成功,返回一个AuthenticationInfo实现;
            return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),new MyByteSource(user.getSalt()),this.getName());
        }
        return null;
    }
}
ログイン後にコピー

の実装この認証は、ログイン時に自動的に呼び出されます。検証中にエラーが発生した場合は、例外が発生します。コントローラー層で例外を受け取り処理しました

コントローラー層ログイン時の例外処理

@PostMapping("/login")
    public String login(String username,String password){
        //获取主体对象
        Subject subject = SecurityUtils.getSubject();
        try {
         //自动调用CustomerRealm 类中的身份验证方法
            subject.login(new UsernamePasswordToken(username,password));
            return "index";
        }catch (UnknownAccountException e){ //接收异常并处理
            e.printStackTrace();
            model.addAttribute("msg","用户名有误,请重新登录");
        }catch (IncorrectCredentialsException e){//接收异常并处理
            e.printStackTrace();
            model.addAttribute("msg","密码有误,请重新登录");
        }
        return "login";
    }
ログイン後にコピー

1.2.6、しろキャッシュ設定

ユーザーがログインした後は、ユーザー情報とロール/権限を毎回確認する必要がないため、効率が向上します。

デフォルトのキャッシュ構成

キャッシュ管理を有効にします。 hiroConfig の getRealm() メソッド

 @Bean
    public Realm getRealm(){
        CustomerRealm customerRealm = new CustomerRealm();
        //开启缓存管理
        customerRealm.setCacheManager(new EhCacheManager());
        //开启全局缓存
        customerRealm.setCachingEnabled(true);
        //开启认证缓存
        customerRealm.setAuthenticationCachingEnabled(true);
        customerRealm.setAuthenticationCacheName("authenticationCache");
        //开启权限缓存
        customerRealm.setAuthorizationCachingEnabled(true);
        customerRealm.setAuthorizationCacheName("authorizationCache");
        return customerRealm;
    }
ログイン後にコピー

reid と統合されたキャッシュについてはここでは説明しませんが、ソース コードに配置されています。ソース コードは以下にありますので、ご自身で確認してください。

1.2 .7、ホームページのインデックス.html 設定

ここでタグを使用して、認証が必要な領域、またはアクセスに必要なロールや権限を決定します

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
                xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <link rel="shortcut icon" href="#">
</head>
<body>
<h1>index</h1>
<a href="/logout">退出</a>
<div>
    <a href="/main">main</a> | <a href="/manage">manage</a> | <a href="/admin">admin</a>
</div>
<!--获取认证信息-->
用户:<span shiro:principal=""></span><hr>
<!--认证处理-->
<span shiro:authenticated=""><hr>
    显示认证通过内容
</span>
<span shiro:notAuthenticated=""><hr>
    没有认证时 显示
</span>
<!--授权角色-->
<span shiro:hasRole="admin"><hr>
    admin角色 显示
</span>
<span shiro:hasPermission="user:*:*"><hr>
    具有用户模块的"user:*:*"权限 显示
</span>
</body>
</html>
ログイン後にコピー

1.3. 簡単なテスト

SpringBootがShiroを統合して権限制御を実装する方法

#1.3.1. 管理者ロールのすべての権限のテスト

SpringBootがShiroを統合して権限制御を実装する方法##1.3. 2. ロールと権限なしでテスト

##1.3.3. ロールと権限なしのテストSpringBootがShiroを統合して権限制御を実装する方法

##

以上がSpringBootがShiroを統合して権限制御を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート