springboot集成springsecurity + jwt的使用

news2025/2/25 18:03:38

当项目中要用到用户的认证及权限的时候我们一般会使用 springSecurity来解决

引入

引入很简单

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>5.4.2</version>
        </dependency>

先来看一下流程(认证流程)只是认证,不管权限
在这里插入图片描述
步骤是这样的:

  1. 用户提交用户名和密码, 由UsernamePasswordAuthenticationFilter 接收, 并由 AuthenticationManager 把它封装成一个 Authentication对象,注意, 此时 Authentication 对象中只用 用户提交的 用户名和密码
  2. 然后一直向后面传,一直到 UserDetailsService 的接口中, 从数据库中查到用户在数据库中的用户名,并通过用户名, 查到用户的所有信息, 并写入的 UserDetails 的类中
  3. 然后, 会通过 PasswordEncoder 来对比, Authentication中用户提交的密码,和 在数据库中查到的 UserDetails中的用户的 密码是否一至
    4.最后,在securityContentHolder.getContext().setAuthentication(Authication),就把认证的对象写入到了上下文中

初级用法(只管认证,先不管权限)

从上面的步骤中, 我们可以看到, 认证方面比较重要的是 UserDetailsService 接口, 以及 PassEncoder 接口,一个是用来从数据库中拿到数据, 另一个是用来对比用户的输入是否正确 其中还会用到一个 UserDetails 的实体类的接口

当我们引入之后, 项目上的把的访问地址, 就会受到 springsecurity 的保护了, 当你请求任何接口时, 就会跳转到登录页面的, 用户名是 user , 密码是在控制台中打印出来的, 拿来用就可以了, 这当然不是我们要用的
我们说的初级用法是 从数据库中查到数据, 然后登录

实现
建一个用户表, 主要要有用户名和密码字段, 然后用 mybatisplus 生成出代码, 这个不是重点
在这里插入图片描述
接着, 我们要新建一个 UserDetails 的实例 SecurityUserDetails ,实现接口中的所有方法, 并添加一下后面要用的属性
在这里插入图片描述

package com.huang.security.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SecurityUserDetails implements UserDetails {

    private SysUser sysUser;    //这个是自已添加的属性, 主要是用来存放从数据库中查到的用户的信息

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        //return null;
        //把这个方法的返回值, 改写成 sysUser 的password返回
        return sysUser.getPassword();
    }

    @Override
    public String getUsername() {
        //return null;
        //把这个方法的返回值,改成 sysUser 的 username的返回值
        return sysUser.getUserName();
    }

    @Override
    //注意, 这里是是否没有过期
    public boolean isAccountNonExpired() {  //把这里的是否 没有过期返回 true
        return true;
    }

    @Override
    //注意, 这里是是否没有锁   改成返回 true
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    //注意, 这里是是否认证没有过期   改成返回 true
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    //注意, 这里是是当前用户是否可以使用  改成返回 true
    public boolean isEnabled() {
        //return (Boolean)sysUser.getStatus();
        return true;
    }
}

实体类创建好之后, 我们就要在 UserDetailSerivce 接口中返回 新建的 SecurityUserDetails 实例
注意,这里只是通过用户我名称, 得到了用户的信息, 并且, 这个 loadUserByUsername() 的方法,是springSecurity 中帮我们调用的, 参数是自动传入的
在这里插入图片描述

package com.huang.security.service.impl;

import com.huang.security.mapper.SysUserMapper;
import com.huang.security.pojo.SecurityUserDetails;
import com.huang.security.pojo.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.Objects;

public class SecurityUserDetailServiceImpl implements UserDetailsService {

    @Autowired  //注入SysUserMapper 对象, 用来查找用户的信息
    private SysUserMapper sysUserMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //根据用户名从数据库中查的找到用户的信息, 写入到 返回的 userDetails对象中
        SysUser sysUser = sysUserMapper.selectOneByUserName(s);
        if(Objects.isNull(sysUser)){
            throw new RuntimeException("通过用户名没有查到用户的信息");
        }
        //这里就可以新建一个 UserDetails 对象, 把用户信息先放入了
        SecurityUserDetails userDetails = new SecurityUserDetails();
        userDetails.setSysUser(sysUser);
        //todo 这里其实还可以从数据库中 获取用户的权限信息 写入 userDetails实例中的, 暂时先不考虑这些
        //userDetails.getAuthorities(); 就是获取权限信息的字符串, 后面再说
        return userDetails;
    }
}

上面的是查找到了用户, 接着,就要让证了, 通过 PasswordEncode 接口的实现类来比对, 确定认证, SpringSecurity 有默认的 PasswordEncoder 来处理, 但是不太好用, 我们一般都是使用的 SpringSecurity提供的另外一个类 BCryptPasswordEncoder , 我们只需要注入一下就可以了
下图中, 要在方法上 添加一个 @Bean 注入
在这里插入图片描述
BCryptPasswordEncoder 中, springSecrity 为我们 写好了, 密码的生成方法, 以及 验证密码的方法。
所以, 从这里我们也可以构造我们自己的密码验证方法, 只需要写一个类去实再 PasswordEncoder接口, 并实现其中的两个方法就可以了, 然后注入到 spring容器中
比如 我们可以写一下 MD5PasswordEncoder implement PasswordEncoder 实现使用 Md5 加密和验证的方法,这里就暂且不说了

实现了以上步骤, 最基本的用户认证就算是完成了


前后端分离系统的认证方法
当我们做前后端分离的项目时, 我们一般不会在页面登录, 也就是说没有, springSecurity自带的登录方法。而是写一个登录接口

首先我们要配置一下 springSecurity ,不要使用 表单登录, 不要跳转到 loginpage 不使用 session 不使用 csrf 等
新建一个 springboot的配置类 securityConfig extend要 WebSecurityConfigurerAdapter
说明一下, 这个SecurityConfig 的配置类, 要继承 WebSecurityConfigurerAdapter , 同时还要加上 @EnableSecurity的注解
在这里插入图片描述

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //不使用 csrf
        http.csrf().disable();
        //不通过session获取 securityContext
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.authorizeRequests()
                //对于用户登录接口允许 匿名方问
                .mvcMatchers("/user/login").anonymous()
                //除上面的接口以外, 都需要认证才可以
                .anyRequest().authenticated();
        //http.formLogin() 这一个不要配置, 如果配置的话, 就会跳转到登录页
    }
}

第一步, 通过登录页面 获取token

我们新建一个 UserController 其中写上 /user/login(因为上面配置了 /user/login可以匿名访问) 的方法, 这个方法返回一个 jwtToken 的字符串
在这里插入图片描述
SysUserService中的login方法
在这之前, 我们在 application.yml 中配置一个 jwt的key 的Base64的字符串, 后面好用来生成 jwt 的key
在这里插入图片描述
(这个Base64 的字符串又是怎么来的呢 ? 在 测试方法中生成了一个)
在这里插入图片描述
SysUserService中的login方法 代码如下


package com.huang.security.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huang.security.mapper.SysRolesMapper;
import com.huang.security.mapper.SysRulesMapper;
import com.huang.security.pojo.SecurityUserDetails;
import com.huang.security.pojo.SysRoles;
import com.huang.security.pojo.SysRules;
import com.huang.security.pojo.SysUser;
import com.huang.security.service.SysUserService;
import com.huang.security.mapper.SysUserMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.impl.DefaultClaims;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import java.util.*;

/**
* @author Administrator
* @description 针对表【sys_user】的数据库操作Service实现
* @createDate 2023-06-05 09:44:59
*/
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
    implements SysUserService{

    @Value("${myjwt.keyswithbase64}")  //这里是从application.yml中得到了 jwtkey的字符串
    private String jwtKeysBase64;

    @Autowired(required = false)
    private SysRolesMapper sysRolesMapper;

    @Autowired(required = false)
    private SysRulesMapper sysRulesMapper;

    @Autowired(required = false)  //这个是认证管理对象, 它是通过 SecurityConfig中的方法注入的, 后面说明它
    private AuthenticationManager authenticationManager;

    @Override
    public String login(SysUser user) {
        //从流程图中我们可以知道, Security 会使用 Authentication 对象来封装用户传递过来的 用户名和密码
        //那么我们又是怎么调用认证的方法,并且使用我们 自已生成的 Authentication 对象来作为参数呢
        //Security提供了  AuthenticationManager 类, 它可以在 Configuration中 重写方法, 得到 AuthenticationManager 对象, 并注入bean中
        //然后,调用  authenticationManager的  authenticate(authentication), 在这个方法中传入 authentication 对象
        //authenticate() 方法 内部, 就会自动去做认证, 调用 UserDetailService 中的方法, 从数据库中查找到用户, 并使用 PasswordEncoder 来认证用户
        //如果认证成功, 返回的 该方法返回的对象,其中就可以得到 用户的信息
        //如果认证不成功, 返回的结果是 null
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
		//这里new的时候只是在里面 放入了 username  和 password 两个参数, 当认证通过了之后, Security会把认证过后的信息, 也就是 SecurityDetails 的对象写入  authenticate 对象中, 使用 authenticate.getPrincipal()
        Authentication authenticate = authenticationManager.authenticate(authentication);
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("用户认证失败");
        }
        //如果不为空, 说明用户的认证通过
        //此时就要用 jwt 为用户生token
        SecurityUserDetails userDetails = (SecurityUserDetails)authenticate.getPrincipal();
        SysUser sysUser = userDetails.getSysUser();
		//从认证的信息中获取用户的信息
        SecretKey secretKey = Keys.hmacShaKeyFor(Base64.getDecoder().decode(jwtKeysBase64));
        Claims claims = new DefaultClaims();
        claims.put("userId", sysUser.getId());
        // 把用户的id 和过期时间设置一下, 生成token
        String jwttoken = Jwts.builder().setClaims(claims).setExpiration(new Date(System.currentTimeMillis() + 2 * 60 * 60 * 1000)).signWith(secretKey).compact();
        return jwttoken;
    }

AuthenticationManager 类是怎么得到的, 在哪里注入的?

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtFilter jwtFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //不使用 csrf
        http.csrf().disable();
        //不通过session获取 securityContext
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.authorizeRequests()
                //对于用户登录接口允许 匿名方问
                .mvcMatchers("/user/login").anonymous()
                //除上面的接口以外, 都需要认证才可以
                .anyRequest().authenticated();
        //http.formLogin() 这一个不要配置, 如果配置的话, 就会跳转到登录页
        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean   //注意这里!!!!!!!!!!!!!!!!!!!!!!!!!!!
    		//当我们自定义认证的时候要使用 AuthenticationManager.authention方法来完成认证
    		//重写这个方法再加入@Bean就可以注入使用了
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

到这里, 我们请求 /user/login方法的时候,就得到了一个 jwttoken, 前端存下来之后, 在后面的请求中就可以把这个 token 放在请求头中, 进行请求了


第二步, 带token 去请求其它的接口, 并且在接口中可以得到当前用户的信息
当前端请求其它接口时, header 头中, 带上 token
如:我们在 userController 中请建了一个 接口

	//UserController   path: /user/visit
    @PostMapping("/visit")
    public String visit(HttpServletRequest request){
    	//为什么可以 getAttribute("user") , 因为我们在 过滤器中认证完用户之后, 把它写入到了 reqeust 的属性中
        SysUser sysUser = (SysUser) request.getAttribute("user");
        System.out.println(sysUser);
        //我们同样也可以使用 SecurityContextHolder.getContext().getAuthentication() 得到的是 自定义的
        //SecurityUserDetails 的对象, 它内部也有 Sysuser 的信息 
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        SecurityUserDetails userdetail = (SecurityUserDetails) authentication.getPrincipal();
        SysUser sysUser2 = userdetail.getSysUser();
        System.out.print("sysuer2"+sysUser2);
        return "haha";
    }

实现步骤
我们要创建一个 Filter , 来过滤 header 中的 token 并进生认证 过滤器代码如下

package com.huang.security.filter;

import com.huang.security.pojo.SecurityUserDetails;
import com.huang.security.pojo.SysUser;
import com.huang.security.service.SysUserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.crypto.SecretKey;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Base64;

//这里没有使用 @WebFilter  (也就是说没有 会使用 implement  Filter) 是因为 springboot 的版本太多, 有的版本的 Filter 会无故的执行两次或多次。
//所以我们这里使用了 springboot 提供的一个 OncePerRequestFilter 类, 它可以保证 只执行一次, 当然要注意把它 加入到容器中  使用 @Component注解
//用法和 Filter 的用法是一样的

@Component
public class JwtFilter extends OncePerRequestFilter {

    @Value("${myjwt.keyswithbase64}")
    private String jwtKeysBase64;

    @Autowired
    private SysUserService sysUserService;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        //我们可以从 request 的头中获取token , 但是我们要注意这里, 如果header中没有token , 要让它放行, 不能抛了错误
        //因为我们确实有的请求头是不需要token的, 但是也不用担心, 在SpringSecurity中 还会有后面的过滤器, 对这个请求进行身份的验证,
        String token = httpServletRequest.getHeader("token");
        if(!StringUtils.hasText(token)){
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            //这里必须要使用 return , 如果没有使用 return , 根据洋葱皮的模型, 这个请求经过后面的过滤器之后, 还会回到当前的这个位置继续执
            //行后面的代码, 所在要在这里 return 一下
            return;
        }
        //如果token不为空, 我们就可以解析token, 然后得到用户的信息, 放入 redis中,或者 threadLocal中, 或者放到 request中了
        //解析token
        //获取一个key
        SecretKey secretKey = Keys.hmacShaKeyFor(Base64.getDecoder().decode(jwtKeysBase64));
        Claims claims =  Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token).getBody();
        //这里的 claims 对象, 就是我们在 生成token时写入的 userId 的内容
        //这里可以使用
        SysUser user = sysUserService.getById(claims.get("userId").toString());
        //获取到了user对象  我们要在 SecurityContext中写入, 因为后面的 Security的过滤器,是会使用 SecurityContextHolder来获取认证信息的
        // 调用 SecurityContextHolder.getContext().setAuthentication()时, 发现要传入一个 Authentication 对象,
        // Authentication 是一个接口, 所以我们使用了他的子类  UsernamePasswordAuthenticationToken
        // 同时要注意, 我们在 new UsernamePasswordAuthenticationToken()的时候, 要使用 三个参数的构造函数
        /*Object principal   就是我们自定义的  SecurityUserDetails 的对象
        *     public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
                super(authorities);
                this.principal = principal;
                this.credentials = credentials;
                super.setAuthenticated(true);   //这里为认证信息设置了状态, 后面的Security 的过滤器都会使用
            }
        *
        * */
        SecurityUserDetails userDetails = new SecurityUserDetails();
        userDetails.setSysUser(user);
        //todo  这里的第三个参数 其实是一个 权限的数组, 这里还没有做权限设置, 所在先传 null
        UsernamePasswordAuthenticationToken authention = new UsernamePasswordAuthenticationToken(userDetails, null, null);
        SecurityContextHolder.getContext().setAuthentication(authention);
        //上面的工作完成之后, 就可以放行了
        httpServletRequest.setAttribute("user",user);
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}

上面, 我们新建了一个过滤器, 并在过滤器中, 对用户进行了 token 的认证, 那么我们知道, 一个项目中都是有过滤器链的, 我们自定义的过滤器, 在SecurityContextHolder中写入认证结果, 所以, 我们自定义的过滤器应该放在 Secruity 的认证过滤器之前才对, 怎么才可以放在之前, 放在哪个之前呢
在这里插入图片描述
作法, 我们可以在SecurityConfig的配置文件中 进行设置
在这里插入图片描述
有了上面的操作, 把第一步中的 jwtToken 拿来使用, 请求 /user/visit 接口
在这里插入图片描述在这里插入图片描述
可以看到, 测试是成功的


带用户权限认证的用法

我们从数据库中做 RBAC 的权限认证表, 一共五个表, 下面只捡要的字段创建一下这五个表
用户表 角色表 权限表 用户角色表 角色权限表
权限表字段
在这里插入图片描述
角色表字段
在这里插入图片描述
角色权限表字段
在这里插入图片描述
用户角色表
在这里插入图片描述
用户表字段主要是用户名和password 这里略过

表中数据如下, 用户表
在这里插入图片描述
两个用户 huangjunhui 的角色是 主管 ceozhang 的角色是 ceo
这个是角色表
在这里插入图片描述

这个是用户角色表
在这里插入图片描述
这个是权限表
在这里插入图片描述
角色权限表 可以看到 ceo 有权限1和2 部门管理和测试都可以, 角色主管,就只有测试的功能了
在这里插入图片描述
以上就是 RBAC 的准备工作了

开始 带权限的认证
首先, 我们要修改 Security 的配置类
在这里插入图片描述
之后我们要在 我们自定义的 userDetails 的类中, 也就是 SecruityUserDetails 的数中, 添加 根限相应的属性
在这里插入图片描述
然后, 我们就要在 自定义的 jwtFilter中, 创建UsernamePasswordAuthenticationToken 时候, 把用户的时候其中有三个参数, 把用户的权限信息写入
在这里插入图片描述
在Controller 中注解 @PreAuthorize(“hasAuthority(‘system:dept:list’)”)
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/618984.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为OD机试真题 Java 实现【磁盘容量排序】【2022Q4 100分】,附详细解题思路

一、题目描述 磁盘的容量单位常用的有M&#xff0c;G&#xff0c;T这三个等级&#xff0c;它们之间的换算关系为1T 1024G&#xff0c;1G 1024M&#xff0c;现在给定n块磁盘的容量&#xff0c; 请对它们按从小到大的顺序进行稳定排序&#xff0c;例如给定5块盘的容量&#x…

Linux NGINX^Tomcat 负载均衡 动静分离集群

---------------------NginxTomcat负载均衡、动静分离------------------------- 由于NGINX静态页面处理能力强&#xff08;2-3w并发&#xff09;资源消耗低&#xff0c;但动态页面处理能力弱&#xff0c;所以将其与Apache结合&#xff0c;使用Apache的动态网页能力补足NGINX的…

哨兵2号(Sentinel-2)卫星数据批量处理

李国春 2021 10 11 哨兵2号&#xff08;Sentinel-2&#xff09;数据广受欢迎&#xff0c;数据质量好&#xff0c;还免费。人家欧空局有自己的处理软件&#xff0c;也有控制台命令行的批量处理。RSD也来凑凑热闹沾个光&#xff0c;指不定有人喜欢不同的操作风格&#xff0c;愿意…

毫米波雷达IWR1642和DCA1000 EVM环境搭建

本文以毫米波雷达IWR1642和DCA1000进行环境搭建以及数据采集。 介绍 mmWaveStudio GUI设计用于表征和评估TI Radar器械。mmWaveStudio通过SPI向mmWave设备发送命令来配置和控制mmWave设备。使用DCA 1000 EVM或TSW 1400 EVM板捕获ADC数据&#xff0c;并在Matlab中处理数据&…

RL - 强化学习 马尔可夫奖励过程 (MRP) 的状态价值

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/131084795 GitHub 源码: https://github.com/SpikeKing/Reinforcement-Learning-Algorithm 马尔可夫奖励过程 (MRP) 的状态价值是指在某…

【unity细节】Default constructor not found for type Player(找不到默认构造函数)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;unity细节和bug ⭐Default constructor not found for type Player ⭐ 文章目录 ⭐Default const…

python爬虫入门,10分钟就够了,这可能是我见过最简单的基础教学

一、基础入门 1.1什么是爬虫 爬虫(spider&#xff0c;又网络爬虫)&#xff0c;是指向网站/网络发起请求&#xff0c;获取资源后分析并提取有用数据的程序。 从技术层面来说就是 通过程序模拟浏览器请求站点的行为&#xff0c;把站点返回的HTML代码/JSON数据/二进制数据&…

Fabric.js 使用自定义字体

theme: smartblue 本文简介 点赞 关注 收藏 学会了 如果你使用 Fabric.js 做编辑类的产品&#xff0c;有可能需要给用户配置字体。 这次就讲讲在 Fabric.js 中创建文本时怎么使用自定义字体、在项目运行时怎么修改字体、以及推荐一个精简字体库的工具。 学习本文前&#xff…

征稿|IJCAI‘23大模型论坛,DeepMind EleutherAI Oxford主题报告

第一届LLMIJCAI’23 Symposium征稿中&#xff0c;优秀投稿论文推荐《AI Open》&#xff08;EI检索&#xff09;和 《JCST》(CCF-B)发表。 大规模语言模型&#xff08;LLMs&#xff09;&#xff0c;如ChatGPT和GPT-4&#xff0c;以其在自然语言理解和生成方面的卓越能力&#xf…

调用腾讯API实现人脸美颜

目录 1. 作者介绍2. 人脸美颜基本原理2.1 获取人脸关键点信息2.2 基于皮肤区域的祛斑算法2.3 脸部器官美型处理2.4 美妆处理 3. 实验流程&#xff08;附代码&#xff09;及结果3.1 调用腾讯API流程3.2 安装依赖库3.3 代码实现3.4 实现结果 常见问题报错以及解决方案 1. 作者介绍…

【备战秋招】JAVA集合

集合 前言 一方面&#xff0c; 面向对象语言对事物的体现都是以对象的形式&#xff0c;为了方便对多个对象 的操作&#xff0c;就要 对对象进行存储。 另一方面&#xff0c;使用Array存储对象方面具有一些弊端&#xff0c;而Java 集合就像一种容器&#xff0c;可以动态地把多…

Towards Blockchain-Based Reputation-Aware Federated Learning

Towards Blockchain-Based Reputation-Aware Federated Learning FINE-GRAINED FEDERATED LEARNINGA. Problem StatementB. DefinitionC. Requirements BLOCKCHAIN-BASED REPUTATION-AWARE FL 论文地址&#xff1a;https://www.researchgate.net/profile/Muhammad-Habib-Ur-Reh…

ChatGPT中文版写日报神器【AI使用技巧】

写日报对于打工人来说是一件枯燥无味又不得不做的工作。有了ChatGPT写日报不再是一件苦差事&#xff0c;分分钟搞掂&#xff0c;你不来试一下吗&#xff1f; ChatGPT中文站https://ai-cn.co提问&#xff1a;我是一名服务端程序员&#xff0c;负责维护商城系统&#xff0c;帮我…

HTTPS安全连接的建立过程

HTTP (Hypertext Transfer Protocol) 和 HTTPS (Hypertext Transfer Protocol Secure) 都是用于在 Web 浏览器和服务器之间传输数据的协议。它们之间的主要区别在于安全性。 HTTP 是一种不安全的协议&#xff0c;因为它在传输过程中不对数据进行加密。这意味着如果有人截取了数…

【立体视觉(二)】之对极几何与关键矩阵

【立体视觉&#xff08;二&#xff09;】之对极几何与关键矩阵 一、对极几何二、关键矩阵一&#xff09;本质矩阵与基础矩阵二&#xff09;本质矩阵的求解三&#xff09;本质矩阵的分解三&#xff09;单应矩阵及其求解 此为个人学习笔记&#xff0c;在各处借鉴了不少好图好文&a…

Ubuntu18.04利用astra pro相机实现ORB—SLAM3实时点云稠密建图—上

Ubuntu18.04利用astra pro相机实现ORB—SLAM3实时点云稠密建图—上 前言前期准备—ROS完整安装 OpenCV的安装&#xff08;4.2.0&#xff09;安装依赖C11特性的编译器Pangolin测试pangolin程序 EigenboostORB-SLAM3 前言 建议编译ORB-SLAM3的硬件设备内存配置至少4GB以上&#…

LinuxSCP和SSH命令

scp命令 cp命令&#xff0c;是拷贝的作用&#xff0c;可以实现将文件或者目录拷贝到另外一个位置。 scp命令&#xff0c;也是拷贝的作用&#xff0c;但是是远程拷贝&#xff0c;可以实现将文件或者目录拷贝到另外的一台机器上。 命令格式 # scp file 远程用户名远程服务器:目标…

Midjourney竞品Leap免费试用; Google 刚刚发布10门独立AI课程

&#x1f989; AI新闻 &#x1f680; Midjourney竞品&#xff0c;免费试玩AI图片生成工具Leap&#xff0c;细节还需提升 摘要&#xff1a;Leap是一款免费试玩的AI图片生成工具&#xff0c;用户可以选择不同的生成模型和步长及数量。功能上尚需提高细节把握能力&#xff0c;但…

【genius_platform软件平台开发】第九十七讲:linux设备驱动中信号(signal函数)的异步通知机制

1. 信号的异步通知 意思是:一旦设备就绪,则主动通知应用程序&#xff0c;这样应用程序根本就不需要查询设备状态&#xff0c;这一点非常类似于硬件上“中断”的概念&#xff0c;比较准确的称谓是“信号驱动的异步I/O”。信号是在软件层次上对中断机制的一种模拟&#xff0c;在…

创新升级!深度学习算法注入机器视觉应用,助力工业领域智慧生产

随着人工智能在算力、算法、大数据等方面的技术突破&#xff0c;基于神经网络的深度学习算法在各行各业加速渗透。而制造业作为AI融合创新的主要场景之一&#xff0c;在机器视觉技术的加持下&#xff0c;持续赋能生产线的自动化、智能化升级&#xff0c;赋予工业生产“感知”能…