Rumah  >  Artikel  >  Java  >  Bagaimana SpringBoot menyepadukan Shiro untuk melaksanakan kawalan kebenaran

Bagaimana SpringBoot menyepadukan Shiro untuk melaksanakan kawalan kebenaran

PHPz
PHPzke hadapan
2023-05-16 16:55:40875semak imbas

1. SpringBoot menyepadukan Shiro

Apache Shiro ialah rangka kerja keselamatan Java yang berkuasa dan mudah digunakan yang melaksanakan pengesahan, kebenaran, kata laluan dan pengurusan sesi.

1.1. Pengenalan kepada shiro

Shiro mempunyai komponen teras, iaitu Subject, SecurityManager dan Realms

  • Subjek: setara dengan "pengguna semasa operasi" "Pengguna ini tidak semestinya orang tertentu, tetapi konsep abstrak, menunjukkan apa sahaja yang berinteraksi dengan program semasa, seperti perangkak, skrip, dsb. Semua Subjek terikat kepada SecurityManager, dan semua interaksi dengan Subjek akan diwakilkan kepada SecurityManager Subjek boleh dianggap sebagai fasad SecurityManager adalah pelaksana sebenar;

  • SecurityManager: Ini adalah teras rangka kerja Shiro Semua operasi berkaitan keselamatan akan berinteraksi dengannya.

  • Realms: Bertindak sebagai "jambatan" antara Shiro dan data keselamatan aplikasi Apabila melakukan pengesahan (log masuk) dan kebenaran (kawalan akses) pada pengguna, SecurityManager perlu mendapatkan respons daripada. Realm Bandingkan identiti pengguna untuk menentukan sama ada identiti pengguna itu sah juga perlu mendapatkan peranan/kuasa sepadan pengguna daripada Realm untuk mengesahkan sama ada pengguna boleh menjalankan operasi.

1.2. Pelaksanaan khusus kod

1.2.1. Konfigurasi 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>

shiro digunakan dengan jsp secara lalai, dan di sini ialah shiro menyepadukan thymeleaf Semua pakej balang yang perlu diimport ke dalam shiro untuk menyepadukan thymeleaf

1.2.2 Kelas yang perlu dilaksanakan untuk penyepaduan

  • Secara umumnya, penyepaduan sahaja. perlu melengkapkan dua kelas Hanya laksanakan

  • Satu ialah ShiroConfig dan satu lagi ialah CustomerRealm

  • Jika anda perlu menambah shiro cache dan ia tidak cache terbina dalam tetapi cache redis, anda juga perlu Tulis dua kelas lain

  • Satu ialah RedisCache dan satu lagi ialah RedisCacheManager

1.2 .3. Struktur projek

Bagaimana SpringBoot menyepadukan Shiro untuk melaksanakan kawalan kebenaran

1.2.4, pelaksanaan ShiroConfig

Cache tanpa 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;
    }
}

Kerana ia secara amnya tidak selamat untuk ditetapkan kosongkan kata laluan teks dalam pangkalan data, jadi saya akan menetapkan kata laluan di sini Dengan penyulitan md5, kaedah penyulitan saya ialah: kata laluan = kata laluan + garam + bilangan cincang dan kemudian lakukan penyulitan MD5 Jadi apabila mencipta alam tersuai di sini, anda perlu menetapkan pemadan supaya kata laluan boleh dipadankan dengan jayanya semasa log masuk

1.2 .5. Pelaksanaan 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;
    }
}

akan memanggil pengesahan ini secara automatik semasa log masuk. Jika ralat berlaku semasa pengesahan, pengecualian akan dilaporkan. Saya menerima pengecualian dalam lapisan pengawal dan memprosesnya

dalam lapisan pengawal Pengendalian pengecualian semasa log masuk

@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, konfigurasi cache shiro

mentakrifkan cache shiro Selepas pengguna log masuk, maklumat dan peranan/keizinan penggunanya tidak perlu disemak setiap kali Dengan cara ini Boleh meningkatkan kecekapan

Konfigurasi cache lalai

Dayakan. pengurusan cache dalam kaedah getRealm() dalam ShiroConfig

 @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;
    }

Cache yang disepadukan dengan reids tidak akan dijelaskan di sini sendiri dalam kod sumber Kod sumber di bawah

1.2 .7. Tetapan index.html

Gunakan teg di sini untuk menentukan sama ada kawasan tertentu memerlukan pengesahan atau peranan atau kebenaran yang boleh diakses

<!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 >

Bagaimana SpringBoot menyepadukan Shiro untuk melaksanakan kawalan kebenaran1.3.1 Uji semua kebenaran peranan admin

Bagaimana SpringBoot menyepadukan Shiro untuk melaksanakan kawalan kebenaran 1.3.2 >

1.3.3 Menguji tanpa peranan dan kebenaran

Bagaimana SpringBoot menyepadukan Shiro untuk melaksanakan kawalan kebenaran

Atas ialah kandungan terperinci Bagaimana SpringBoot menyepadukan Shiro untuk melaksanakan kawalan kebenaran. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam