Spring boot+Shiro

spring boot 集成shiro和redis (绝不坑你) spring boot 集成shiro和redis (绝不坑你) 最近两天一直在弄shiro跟spring boot的整合,网上讨论的很多,但是真正搞懂的人很少,都是抄抄抄,我现在就将我这两天的所有结果分享给大家,供大家参考。 跟spring mvc 的集成很相像,但是也有很多不同的地方,主要体现在springboot 跟mvc的配置差异上。配置shiro,如果要跑起来,非常简答,跟... 阅读详情

一、Shiro框架

1、官方文档:http://shiro.apache.org/index.html

shrio是一个基于Java的安全认证框架,是一个轻量级的安全框架,主要的作用是在后端承担认证和授权的工作,可在JavaSE和JavaEE环境中使用

2、shiro架构

在这里插入图片描述

  • Authentication:有时称为“登录”,这是证明用户是他们所说的身份的行为。
  • Authorization:**访问控制的过程,即确定“谁”有权访问“什么”。
  • Session Management:即使在非Web或EJB应用程序中,也管理用户特定的会话。
  • Cryptography:使用密码算法保持数据安全,同时仍然易于使用。

在不同的应用程序环境中,还具有其他功能来支持和加强这些问题,尤其是:

  • Web Support:Shiro的Web支持API可帮助轻松保护Web应用程序。
  • Caching:缓存是Apache Shiro API的第一层公民,可确保安全操作保持快速有效。
  • Concurrency:Apache Shiro的并发功能支持多线程应用程序。
  • Testing:测试支持可以帮助您编写单元测试和集成测试,并确保您的代码将按预期进行保护。
  • “Run As”:一种功能,允许用户采用其他用户的身份(如果允许),有时在管理方案中很有用。
  • “Remember Me”:在整个会话中记住用户的身份,因此他们仅在必要时登录。

在认证过程中有三个核心的对象:Subject,SecurityManager和Realm(s)
在这里插入图片描述

  • Subject:Subject本质上是当前正在执行的用户的安全特定“视图”,是shiro对外的API核心。Subject代表了当前的用户,可以是一个人,但它也可以表示第三方服务,守护程序帐户。

    Subject只是一个门面,其内部有关操作都交给了SecurityManager去执行

  • SecurityManager:是Shiro体系结构的核心,并充当一种“伞”对象,该对象协调其内部安全组件,这些安全组件一起形成对象图。相当于sprintmvc的dispatcherServlet,负责其他组件与shiro的交互

  • Realm:领域充当Shiro与应用程序的安全数据之间的“桥梁”或“连接器”。可以执行身份验证(登录)和授权(访问控制),相当于数据库中的DataSource,可以自定义该类

二、在Springboot中配置shiro

1、导包

<!--shiro-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.3</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-starter</artifactId>
    <version>1.5.3</version>
</dependency>
<!--shiro注解支持需要aop的支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、开启aop的自动代理

sprint:
	aop:
		proxy-target-class: true

3、自定义Realm

@Slf4j
public class ShiroRealm extends AuthorizingRealm {
    @Lazy
    @Resource
    private RedisUtil redisUtil;
    @Autowired
    private SysUserDao sysUserDao;

    /**
     * 重写身份令牌验证方式
     * 若返回false则在执行登录操作时会报org.apache.shiro.authc.pam.UnsupportedTokeException
     * 即不支持的身份令牌
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 权限信息认证(包括角色认证以及权限认证):是用户访问controller的时候才进行验证
     * 触发检测用户权限时才会调用此方法,例如checkRole,checkPermission
     *
     * @param principals 身份信息
     * @return AuthorizationInfo 权限信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    /**
     * 用户信息认证:在用户进行登录的时候进行验证
     *
     * @param auth 用户登录的账号密码信息
     * @return 返回封装了用户信息的 AuthenticationInfo 实例
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
        String token = (String) auth.getCredentials();
        if (token == null) {
            throw new AuthenticationException("token为空!");
        }
        
        // 校验token有效性
        LoginUser loginUser = this.checkUserTokenIsEffect(token);
        //可进行一系列验证。。。
        
        /**
         * 封装用户的登录数据
         */
        return new SimpleAuthenticationInfo(loginUser, token, getName());
    }

    /**
     * 清除当前用户的权限认证缓存
     *
     * @param principals 权限信息
     */
    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

}
SimpleAuthenticationInfo源码解析
  • 构造方法的第一个参数指定了登录的用户数据
  • 第二个参数用来校验第一个参数所指定的用户,一般可为用户的token或password
  • 第三个参数指定了授权的对象名
/**
 * Constructor that takes in a single 'primary' principal of the account and its corresponding credentials,
 * associated with the specified realm.
 * <p/>
 * This is a convenience constructor and will construct a {@link PrincipalCollection PrincipalCollection} based
 * on the {@code principal} and {@code realmName} argument.
 *
 * @param principal   the 'primary' principal associated with the specified realm.
 * @param credentials the credentials that verify the given principal.
 * @param realmName   the realm from where the principal and credentials were acquired.
 */
public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {
    this.principals = new SimplePrincipalCollection(principal, realmName);
    this.credentials = credentials;
}

4、shiro的配置文件

@Slf4j
@Configuration
public class ShiroConfig {

    /**
     * 开启shiro注解支持
     * @return
     */
    @Bean
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 添加注解支持
     * @return
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        //设置安全管理器
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 1、一个URL可以配置多个Filter,使用逗号分隔
     * 2、当设置多个过滤器时,全部验证通过,才视为通过
     * 3、部分过滤器可指定参数,如perms,roles
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 设置安全管理器SecurityManager
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        /**
         * 配置拦截器,顺序拦截,使用链式结构
         * anon:无需认证就可以访问
         * authc:需要认证才可以访问
         * user:需要设置remenberMe=true属性才能访问
         * perms:需要拥有对某个资源的权限才能访问
         * role:需要拥有某个角色的权限才能访问
         */
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        filterChainDefinitionMap.put("/**", "anon");
        //设置shiro的拦截器
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("shiroRealm") ShiroRealm shiroRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联Realm
        securityManager.setRealm(shiroRealm);
        return securityManager;
    }
    /**
     * 自定义身份认证Realm
     * @return
     */
    @Bean
    public ShiroRealm shiroRealm() {
        return new ShiroRealm();
    }
}

三、Shiro的认证过程

首先是先将接收到的用户输入的数据生成UsernamePasswordToken类或者该类的子类,获取shiro的Subject对象执行subject.login(usernamePasswordToken)方法

Subject subject = SecurityUtils.getSubject();
    UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.get("email").toString(), user.get("password").toString());
     try {
        subject.login(usernamePasswordToken);
     } catch  (UnknownAccountException uae) {
     	return ResponseEntity.ok(new ResultOK(500,"账号不存在!"));
     } catch (IncorrectCredentialsException ice) {
     	return ResponseEntity.ok(new ResultOK(500,"账号或密码有误!"));
     } catch (LockedAccountException lae) {
     	return ResponseEntity.ok(new ResultOK(500,"账号被锁定!"));
     } catch (AuthenticationException ae) {
     	return ResponseEntity.ok(new ResultOK(500,"用户认证失败!"));
     } catch (Exception e) {
     	return ResponseEntity.ok(new ResultOK(500,e.getMessage()));
     }
     return ResponseEntity.ok(new ResultOK(200,"登录成功!");

这里的usernamePasswordToken(以下简称token)就是用户名和密码的一个结合对象,然后调用subject的login方法将token传入开始认证过程。底层调用的其实是securityManager的login方法:

Subject subject = securityManager.login(this, token);

再往下看securityManager的login方法内部:

public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
    AuthenticationInfo info;
     try {
            info = authenticate(token);
     } catch (AuthenticationException ae) {
            try {
                onFailedLogin(token, ae, subject);
     } catch (Exception e) {
                if (log.isInfoEnabled()) {
                    log.info("onFailedLogin method threw an " +
                            "exception.  Logging and propagating original AuthenticationException.", e);
     }
            }
            throw ae; //propagate
     }
        Subject loggedIn = createSubject(token, info, subject);
     onSuccessfulLogin(token, info, loggedIn);
     return loggedIn;
}

上面代码的关键在于:

info = authenticate(token);

即将token传入authenticate方法中得到一个AuthenticationInfo类型的认证信息。以下是authenticate方法的具体内容:

public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
    if (token == null) {
        throw new IllegalArgumentException("Method argument (authentication token) cannot be null.");
    }
    log.trace("Authentication attempt received for token [{}]", token);
    AuthenticationInfo info;
    try {
        info = doAuthenticate(token);
    if (info == null) {
            String msg = "No account information found for authentication token [" + token + "] by this " +
                    "Authenticator instance.  Please check that it is configured correctly.";
    throw new AuthenticationException(msg);
    }
    } catch (Throwable t) {
        AuthenticationException ae = null;
    if (t instanceof AuthenticationException) {
            ae = (AuthenticationException) t;
    }
        if (ae == null) {
            //Exception thrown was not an expected AuthenticationException.  Therefore it is probably a little more
    //severe or unexpected.  So, wrap in an AuthenticationException, log to warn, and propagate: String msg = "Authentication failed for token submission [" + token + "].  Possible unexpected " +
                    "error? (Typical or expected login exceptions should extend from AuthenticationException).";
    ae = new AuthenticationException(msg, t);
    if (log.isWarnEnabled())
                log.warn(msg, t);
    }
        try {
            notifyFailure(token, ae);
    } catch (Throwable t2) {
            if (log.isWarnEnabled()) {
                String msg = "Unable to send notification for failed authentication attempt - listener error?.  " +
                        "Please check your AuthenticationListener implementation(s).  Logging sending exception " +
                        "and propagating original AuthenticationException instead...";
    log.warn(msg, t2);
    }
        }
        throw ae;
    }
    log.debug("Authentication successful for token [{}].  Returned account [{}]", token, info);
    notifySuccess(token, info);
    return info;
}

首先就是判断token是否为空,不为空再将token传入doAuthenticate方法中:

protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
    assertRealmsConfigured();
    Collection<Realm> realms = getRealms();
    if (realms.size() == 1) {
        return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
    } else {
        return doMultiRealmAuthentication(realms, authenticationToken);
    }
}

这一步是判断是有单个Reaml验证还是多个Reaml验证,单个就执行doSingleRealmAuthentication()方法,多个就执行doMultiRealmAuthentication()方法。
一般情况下是单个验证:

protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
    if (!realm.supports(token)) {
        String msg = "Realm [" + realm + "] does not support authentication token [" +
                token + "].  Please ensure that the appropriate Realm implementation is " +
                "configured correctly or that the realm accepts AuthenticationTokens of this type.";
        throw new UnsupportedTokenException(msg);
    }
    AuthenticationInfo info = realm.getAuthenticationInfo(token);
    if (info == null) {
        String msg = "Realm [" + realm + "] was unable to find account data for the " +
                "submitted AuthenticationToken [" + token + "].";
        throw new UnknownAccountException(msg);
    }
    return info;
}

这一步中首先判断是否支持Realm,只有支持Realm才调用realm.getAuthenticationInfo(token)获取info。

public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    AuthenticationInfo info = getCachedAuthenticationInfo(token);
    if (info == null) {
        //otherwise not cached, perform the lookup:
        info = doGetAuthenticationInfo(token);
        log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
        if (token != null && info != null) {
            cacheAuthenticationInfoIfPossible(token, info);
        }
    } else {
        log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
    }
    if (info != null) {
        assertCredentialsMatch(token, info);
    } else {
        log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
    }
    return info;
}

首先查看Cache中是否有该token的info,如果有,则直接从Cache中去即可。如果是第一次登录,则Cache中不会有该token的info,需要调用doGetAuthenticationInfo(token)方法获取,并将结果加入到Cache中,方便下次使用。而这里调用的doGetAuthenticationInfo()方法就是我们在自定义的Realm中重写的方法,具体的内容是自定义了对拿到的这个token的一个处理的过程:

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    if (authenticationToken.getPrincipal() == null)
        return null;
    String email = authenticationToken.getPrincipal().toString();
    User user = userService.findByEmail(email);
    if (user == null)
        return null;
    else return new SimpleAuthenticationInfo(email, user.getPassword(), getName());
}

这其中进行了几步判断:可以判断传入的用户名是否为空,判断传入的用户名在本地的数据库中是否存在,该用户是否有效等验证,验证不通过则返回一个Exception。通过之后则生成一个包括传入用户名和密码的info,注意此时关于用户名的验证已经完成,接下来进入对密码的验证。
将这一步得到的info返回给getAuthenticationInfo方法中的

assertCredentialsMatch(token, info);

此时的info是正确的用户名和密码的信息,token是输入的用户名和密码的信息,经过前面步骤的验证过程,用户名此时已经是真是存在的了,这一步就是验证输入的用户名和密码的对应关系是否正确。

protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
    CredentialsMatcher cm = getCredentialsMatcher();
    if (cm != null) {
        if (!cm.doCredentialsMatch(token, info)) {
            //not successful - throw an exception to indicate this:
            String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
            throw new IncorrectCredentialsException(msg);
        }
    } 
    else {
        throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
                "credentials during authentication.  If you do not wish for credentials to be examined, you " +
                "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
    }
}

这一步验证完成之后,整个shrio认证的过程就结束了。

Spring Boot整合Shiro 记录一次简单易懂的Spring Boot整合Shiro的过程,实现用户认证、授权、密码加密、权限管理功能。 阅读详情

相关推荐

spring boot整合redis,实现shiro的CacheManager

接着上一篇博客来讲:Spring Boot整合jpa,Shiro进行权限管理 Shiro默认整合了EhCache,来实现缓存,如果我们想用redis替换EhCache来实现缓存怎么做了?我们可以从Shiro的源码来找到一些端倪。我们可以模拟EhCacheManager的实现方式,EhCacheManager类定义如下: public class EhCacheManager implement

牛奋lch 1万+

Shiro-官方文档及使用

*** 自定义reamlm*///登陆认证//强转为用户名密码token//得页面传的登录名//从数据库中查询登录名if (user!= null){//封装到认证对象中//第一个参数:安全数据(user对象)//第二个参数:密码(数据库密码)//第三个参数:当前调用realm域的名称(类名即可)}}// 授权访问校验if (user!=null) {//根据用户的ID从数据库中查询出权限模块//将查询出的模块名称添加到set集合中}

sebeefe的博客 1988

spring boot + shiro + redis 整合(完整)

spring boot + shiro + redis 整合(完整)什么是shiro?数据库设计 什么是shiro? shiro是一个Java平台的开源权限框架,用于认证和访问授权。具体来说,满足对如下元素的支持: 用户,角色,权限(仅仅是操作权限,数据权限必须与业务需求紧密结合),资源(url) 用户分配角色,角色定义权限 访问授权时支持角色或者权限,并且支持多级的权限定义 数据库设计 数据...

qq_45275875的博客 7800

Shiro学习文档

Shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架。 **Apache Shiro™** is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy

qq_42191775的博客 1784

spring boot整合Shiro实现单点登录

前面的博客中,我们说道了Shiro的两个最大的特点,认证和授权,而单点登录也是属于认证的一部分,默认情况下,Shiro已经为我们实现了和Cas的集成,我们加入集成的一些配置就ok了。 1、加入shiro-cas包 org.apache.shiro shiro-cas 1.2.4

牛奋lch 4万+

spring-boot集成shiro

spring-boot集成shiro

ltx1143181624的博客 807

Apache Shiro官方构架文档中文翻译

本文翻译自Shiro官方文档,文章介绍了Shrio的架构,详细讲解了Shiro中的关键组件和概念。建议在深入学习Shiro之前仔细理解本文。 原文地址:http://shiro.apache.org/architecture.html。 Apache Shiro Architecture ApacheShiro的设计目标,是通过直觉化的设计,来简化程序安全开发,并且简单易用。S...

稀有气体的技术博客 3万+

Spring Boot 整合 Shiro 实现 Token 的登录和认证

Spring Boot 2.X 实战--Shiro (Token)登录和验证 主要介绍了 Spring Boot 整合 Spring Security 实现 Token 的登录和认证,这一小节中,我们将实现 Spring Boot 整合 Shiro 实现 Token 的登录和认证。 目录结构 1)Apache Shiro 简介 2)Shiro 项目配置 2.1)项目配置 3)开始...

u011202388的博客 6415

spring boot 集成 shiro

spring boot 集成 shiro 就用 org.apache.shiro->shiro-spring-boot-web-starter

小徕虫的博客 3087

shiro官方文档(中文)

apache-shiro-1.2.x-reference(中文版) 。

shiro 安全框架--最好的中文配置文档

shiro 安全框架--最好的中文配置文档,讲了shiro的配置步骤

Shiro - Shiro简介;Shiro与Spring Security区别;Spring Boot集成Shiro

以下引自百度百科Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。三个核心组件:Subject,SecurityManager 和 Realms。...

MinggeQingchun的博客 4万+

Apache_Shiro中文开发说明文档.docx

非常全面的Shiro中文开发文档。

Spring Boot 整合 Shiro

Spring Boot 整合 Shiro 1. Shiro 简介 Apache Shiro 是一个强大的简单易用的 Java 安全框架,主要用来更便捷的认证、授权、加密、会话管理、与 Web 集成、缓存等; Shiro 使用起来小而简单; Shiro 依赖性低,不需要任何框架和容器,Shiro 不仅可以实现 Web 应用的权限管理,还可以实现 C/S 系统,分布式系统权限管理; Shiro 属于轻量框架。 2. Shiro 核心功能 1. 主要功能 Shiro 主要有三大功能模块: Subject:

beastars1的博客 258

shiro文档以及代码

shiro文档以及代码

如何使用JMeter进行大模型的压力测试?

使用JMeter进行大模型的压力测试,核心是通过模拟高并发请求,测试大模型在极限负载下的性能表现(如响应时间、吞吐量、错误率、资源瓶颈等)。通过以上步骤,可系统性评估大模型在高压下的性能极限,为优化模型(如量化、蒸馏)、扩容硬件(增加GPU)或调整接口限流策略提供数据依据。)、请求方式(POST)、认证方式(API Key放在Header)、请求参数(作用:避免瞬间高压压垮系统,更精准找到瓶颈点。等)、响应格式(同步/流式)。需获取:API地址(如。通过CSV文件引入不同。

alankuo的专栏 790

Spring Boot 整合 Shiro详解

创建一个自定义Realm类,用于实现用户认证和授权的逻辑:java复制import orgthrow new UnknownAccountException("用户不存在");} }throw new UnknownAccountException("用户不存在");} }throw new UnknownAccountException("用户不存在");

ning的博客 2346

ZYNQ Linux下UIO中断配置避坑实录:从设备树修改到用户层测试(Vivado 2018.2)

本文详细解析了ZYNQ Linux下UIO中断配置的全流程,从设备树修改到用户层测试,特别针对Vivado 2018.2环境中的常见陷阱提供解决方案。内容涵盖中断号配置规则、用户空间中断处理程序编写以及性能优化技巧,帮助开发者高效实现硬件中断的用户空间控制。

weixin_31854867的博客 334

Spring Boot学习之Shiro

Apache Shiro 是一个Java 的安全(权限)框架。Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等。Shiro官网。

缘友一世的博客 2712

11-4 AEB 算法原理及系统组成

本专题旨在探讨如何利用仿真软件开发自动紧急制动系统AEB,主要通过整理开发流程,实现从需求到验证的全流程掌握,为后续开发提供支持;同时,研究了如何在汽车自动驾驶仿真工具中开发自己的算法,并解决了从ISO、E-CNAP、GB/T以及交通法规等提炼出功能需求的问题,以快速实现原型模型的开发。本专题重点讲解了AEB的工作原理、系统/软件架构和需求、算法模型及实现、CCRs/CCRb/CCRm建模与仿真、VRU-AEB-B/P/M建模与仿真,同时还提供了测试用例,期待将AEB算法成功地产品化。

AIgraphX 8552

GEE 案例:基于陆地卫星8号(大气层顶反射率数据)LANDSAT/LC08/C02/T1_TOA的生态遥感指数RSEI计算、可视化和下载

摘要:基于GEE的遥感生态指数(RSEI)计算方法 本文介绍了利用Google Earth Engine(GEE)平台计算遥感生态指数(RSEI)的全流程方法。主要内容包括:研究区域定义、Landsat8数据获取与去云预处理、关键生态指标计算(地表温度LST、植被指数NDVI、湿度指数WET和建筑指数NDBSI)、主成分分析(PCA)降维处理,以及结果可视化与数据导出。通过结合多源遥感指标并采用归一化处理,构建了综合反映区域生态环境质量的RSEI指数。该方法为生态环境监测提供了高效的技术方案,所有计算过程均

此星光明博客 450
上一篇: Redis启动服务端与客户端
下一篇: SpringCloud介绍
jf-lin
博客等级 码龄7年 37粉丝 49原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值