04-获取认证的用户身份信息
存储用户信息的方式
获取用户信息的流程
用户提交账号和密码后,DaoAuthenticationProvider
调用UserDetailsService
接口实现类的loadUserByUsername()
方法,该方法可以接收请求参数username
的值,然后根据该值查询用户信息,最后将账号,密码,权限
封装到UserDetails
对象中并返回给Spring security框架
public interface UserDetailsService {// 根据用户名获取用户信息的方法,不同的实现类对应不同的实现方式UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
// UserDetails是用户信息接口
public interface UserDetails extends Serializable {Collection<? extends GrantedAuthority> getAuthorities();String getPassword();String getUsername();boolean isAccountNonExpired();boolean isAccountNonLocked();boolean isCredentialsNonExpired();boolean isEnabled();
}
基于内存的方式存储用户信息
InMemoryUserDetailsManager
是UserDetailsService
接口的实现类,可以将用户信息以硬编码的方式存储在内存中并封装到UserDetails
对象中
package com.xuecheng.auth.config;
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic UserDetailsService userDetailsService() {// 1. 配置用户信息服务InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();// 2. 创建用户信息这里暂时写死,后面需要从数据库中动态查询, Kyle的权限是p1,Lucy的权限是p2// User是Spring Security提供的工具类manager.createUser(User.withUsername("Kyle").password("123").authorities("p1").build());manager.createUser(User.withUsername("Lucy").password("456").authorities("p2").build());return manager;}// 设置密码比对的规则@Beanpublic PasswordEncoder passwordEncoder() {// 采用明文的方式直接比对return NoOpPasswordEncoder.getInstance();}protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/r/**")// 表示"/r/**"开头的请求需要认证.authenticated().anyRequest().permitAll().and().formLogin().successForwardUrl("/login-success");// 配置退出登录页面,认证成功后访问/logout可退出登录http.logout().logoutUrl("/logout");}
}
基于数据库存储用户信息和密码编码格式
实际开发中认证服务所需要的用户信息都是存储在数据库中,所以我们要从数据库中查询用户信息
第一步:屏蔽掉原先的InMemoryUserDetailsManager
, 自定义一个UserDetailsService
接口的实现类UserDetailsImpl
并重写loadUserByUsername()
方法,该方法可以接收URL中携带的请求参数username
的值
- 我们重写方法的业务逻辑是根据用户的账号名从数据库中查询对应的用户信息,然后将
账号,密码,用户权限
信息封装到UserDetails
类型的对象中并返回给Spring Security框架
,不设置权限会报Cannot pass a null GrantedAuthority collection
@Service
public class UserDetailsImpl implements UserDetailsService {@AutowiredXcUserMapper xcUserMapper;/**** @param name 用户输入的登录账号* @return UserDetails* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {// 根据username去XcUser表中查询对应的用户信息XcUser user = xcUserMapper.selectOne(new LambdaQueryWrapper<XcUser>().eq(XcUser::getUsername, name));// 返回NULL表示用户不存在,SpringSecurity会帮我们处理即抛出异常表示用户不存在if (user == null) {return null;}// 设置用户权限// String[] authorities= {"test"};// 取出数据库中用户的密码String password = user.getPassword();// 将用户名和密码以及用户权限(权限必须要设置)封装成一个UserDetails对象,然后返回即可return User.withUsername(user.getUsername()).password(password).authorities("test").build();}
}
第二部:Spring Security框架将URL中的请求参数password
的值即用户的登陆密码和UserDetails
对象中从数据库中查询到的密码进行比对
- 数据库中的密码是加密过的,但用户登陆时输入的密码是明文形式,所以我们要修改
WebSecurityConfig
配置类中的密码格式器PasswordEncoder
指定的密码校验方式
密码格式 | 描述 |
---|---|
NoOpPasswordEncoder | 表示通过明文的方式比较密码 |
BCryptPasswordEncoder | 表示先将用户输入的密码编码为BCrypt格式 后才与数据库中的密码进行比对 |
@Bean
public PasswordEncoder passwordEncoder() { // return NoOpPasswordEncoder.getInstance();return new BCryptPasswordEncoder();
}
BCryptPasswordEncoder
原理: 虽然同样的原始密码可以对应不同的Hash值,但是比对密码时如果调用它提供的matches
方法即使Hash值不同但校验是正确的
- 先将数据库表中用户密码的存储方式改为
BCrype格式
, 申请令牌时输入的密码需要的还是明文形式
public static void main(String[] args) {String password = "123456";BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();for (int i = 0; i < 5; i++) {// 每个计算出的Hash值都不一样String encodePsw = encoder.encode(password);// 虽然Hash值不一样,但是校验是可以通过的System.out.println("转换后密码:" + encodePsw + "比对情况:" + encoder.matches(password, encodePsw));}
}// 转换后密码:$2a$10$6hbvtCtgcISvbBHJ.UnhPO1io7StF.ySPkmAvzO/efvNmHVVJZOeK比对情况:true
// 转换后密码:$2a$10$ufYW9qXSAk0N201B/wCR7uGrzygawnwXtyL2vKpDLAOCOkF33sGnK比对情况:true
// 转换后密码:$2a$10$DEaVxYHakIE/kDvAU4eC7OZ7c9kqKBJedClVxDPnYH.zwuZvCRnzm比对情况:true
// 转换后密码:$2a$10$s2qgaKGgULYQ7tce2u6TIeHopap4HqfyghJYu1vdDZ2WcNk70ykFe比对情况:true
// 转换后密码:$2a$10$XQaQJIfXyd/UvMHC..uBNuDXNVrZHnEGn.tW0oSB6WVjdsZLFpkGq比对情况:true
由于我们修改了框架密码的校验方式,所以还需要将认证服务批准接入的客户端的密钥
也更改为BCrypt的编码格式
// 配置客户端的详情信息
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory()// 使用in-memory存储.withClient("XcWebApp")// 客户端的Id.secret(new BCryptPasswordEncoder().encode("XcWebApp"))//客户端密钥转为BCrypt格式.resourceIds("xuecheng-plus")//资源列表.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")// 允许的授权类型.scopes("all")// 允许的授权范围.autoApprove(false)//false跳转到授权页面 .redirectUris("http://localhost/");//客户端接收授权码的重定向地址
}
第三步:重启认证服务使用HttpClient通过密码模式申请令牌,要保证登陆的明文密码在数据库中有对应的BCrypt格式的加密密码
###### 密码模式
POST localhost:53070/auth/oauth/token?client_id=XcWebApp&client_secret=XcWebApp&grant_type=password&username=Kyle&password=111111
第四步:查看服务端响应的结果
// 输入正确的账号密码即可成功申请令牌
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsieHVlY2hlbmctcGx1cyJdLCJ1c2VyX25hbWUiOiJLeWxlIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTY3ODQ1MTUxNiwiYXV0aG9yaXRpZXMiOlsidGVzdCJdLCJqdGkiOiJkOWUwYjU0ZS03Zjg4LTQ2NjAtYjFlZS04ZWQzYjYzZmQwNjMiLCJjbGllbnRfaWQiOiJYY1dlYkFwcCJ9.NaS3hmpDtX3zkXvnZWoo9ROEWgYeA6GoxBzy_lOxzvA",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsieHVlY2hlbmctcGx1cyJdLCJ1c2VyX25hbWUiOiJLeWxlIiwic2NvcGUiOlsiYWxsIl0sImF0aSI6ImQ5ZTBiNTRlLTdmODgtNDY2MC1iMWVlLThlZDNiNjNmZDA2MyIsImV4cCI6MTY3ODcwMzUxNiwiYXV0aG9yaXRpZXMiOlsidGVzdCJdLCJqdGkiOiI5YjE4OTUwOS1iYmEzLTRkMTctYTNkNC05OWQwZGI5NjU0MDAiLCJjbGllbnRfaWQiOiJYY1dlYkFwcCJ9.548w5CdQiIU5_k1qRBjzM-PMBqy-XX3zr17tQS6g6CM",
"expires_in": 7199,
"scope": "all",
"jti": "d9e0b54e-7f88-4660-b1ee-8ed3b63fd063"
}// 输入错误的密码,申请令牌失败
{
"error": "invalid_grant",
"error_description": "用户名或密码错误"
}
扩展用户身份信息的方式(UserDetails)
用户表中除了存储用户的账号密码还有其他信息,但是UserDetails
接口中只有username、password
字段,这样JWT令牌中也只会写入用户的账号和密码信息
- 在认证阶段
DaoAuthenticationProvider
会调用我们自定义的UserDetailsService
接口实现类的loadUserByUsername()
方法查询数据库表中用户全部的信息,但是UserDetails
中只能存储账号和密码
public interface UserDetails extends Serializable {Collection<? extends GrantedAuthority> getAuthorities();String getPassword();String getUsername();boolean isAccountNonExpired();boolean isAccountNonLocked();boolean isCredentialsNonExpired();boolean isEnabled();
}
由于JWT令牌中用户身份信息来源于UserDetails
, 所以我们只能把UserDetails中包含的用户信息写入JWT令牌中,想要扩展用户的身份信息有两种方式
修改源码
: 对框架提供的UserDetails的属性进行扩展,使之包括更多的自定义属性存储Json(推荐)
: 我们还可以将用户的全部信息转为Json数据存储到UserDetails的username属性(需要脱敏)
,并不一定要只存储用户账号
@Service
public class UserDetailsImpl implements UserDetailsService {@AutowiredXcUserMapper xcUserMapper;/**** @param name 用户输入的登录账号* @return UserDetails* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {// 根据username去XcUser表中查询对应的用户信息XcUser user = xcUserMapper.selectOne(new LambdaQueryWrapper<XcUser>().eq(XcUser::getUsername, name));// 返回NULL表示用户不存在,SpringSecurity会帮我们处理即抛出异常表示用户不存在if (user == null) {return null;}// 设置用户权限// String[] authorities= {"test"};// 取出数据库中用户的密码String password = user.getPassword();// 将查询到的用户信息映射的XcUser对象转为Json,注意对用户的敏感信息要进行脱敏user.setPassword(null);String userString = JSON.toJSONString(user);// 将用户名和密码以及用户权限(权限必须要设置)封装成一个UserDetails对象,然后返回即可return User.withUsername(userString).password(password).authorities("test").build();}
}
重启认证服务,使用密码模式重新获取令牌
// 密码模式
POST localhost:53070/auth/oauth/token?client_id=XcWebApp&client_secret=XcWebApp&grant_type=password&username=Kyle&password=111111
访问校验接口
查看JWT令牌中的内容,此时令牌的user_name
属性中包含了查询到的用户全部信息(密码为null)
// 访问校验接口
POST localhost:53070/auth/oauth/check_token?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsieHVlY2hlbmctcGx1cyJdLCJ1c2VyX25hbWUiOiJ7XCJjb21wYW55SWRcIjpcIjEyMzIxNDE0MjVcIixcImNyZWF0ZVRpbWVcIjpcIjIwMjItMDktMjhUMDg6MzI6MDNcIixcImlkXCI6XCI1MlwiLFwibmFtZVwiOlwiS2lraVwiLFwicGFzc3dvcmRcIjpcIiQyYSQxMCQwcHQ3V2xmVGJuUERUY1d0cC8uMk11NUNUWHZvaG5OUWhSNjI4cXE0Um9LU2MwZEdBZEVnbVwiLFwic2V4XCI6XCIxXCIsXCJzdGF0dXNcIjpcIlwiLFwidXNlcm5hbWVcIjpcIkt5bGVcIixcInV0eXBlXCI6XCIxMDEwMDJcIn0iLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNjc4NDUyMzU0LCJhdXRob3JpdGllcyI6WyJ0ZXN0Il0sImp0aSI6Ijc2MDc0MDI4LTBiM2MtNDQ4Mi1hN2Y0LTc1NDI3ZTA2OTFjMSIsImNsaWVudF9pZCI6IlhjV2ViQXBwIn0._GKfGE2s5k0n6VC4_RKQrzdzydWY-WtX3Q_Hc4DxQ1g{"aud": ["xuecheng-plus"],"user_name": "{\"companyId\":\"1232141425\",\"createTime\":\"2022-09-28T08:32:03\",\"id\":\"52\",\"name\":\"Kiki\",\"password\":\"$2a$10$0pt7WlfTbnPDTcWtp/.2Mu5CTXvohnNQhR628qq4RoKSc0dGAdEgm\",\"sex\":\"1\",\"status\":\"\",\"username\":\"Kyle\",\"utype\":\"101002\"}","scope": ["all"],"active": true,"exp": 1678452354,"authorities": ["test"],"jti": "76074028-0b3c-4482-a7f4-75427e0691c1","client_id": "XcWebApp"
}
资源服务获取用户身份信息
现在认证服务生成JWT令牌的user_name
属性已经存储用户JSON格式的信息,在资源服务中就可以取出该JSON格式的内容转换为用户对象去使用
第一步: 在content-api
工程中写一个工具类SecurityUtil
用来在各个微服务中获取到当前登录用户信息的对象
@Slf4j
public class SecurityUtil {public static XcUser getUser() {try {// 通过SecurityContextHolder获取user_name属性的值即包含用户信息的Json字符串Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();if (principal instanceof String) {// 将包含用户信息的Json字符串转换为XcUser对象String userJson = principal.toString();XcUser xcUser = JSON.parseObject(userJson, XcUser.class);return xcUser;}} catch (Exception e) {log.error("获取当前登录用户身份信息出错:{}", e.getMessage());e.printStackTrace();}return null;}// 这里使用内部类是为了不让content工程去依赖auth工程@Datapublic static class XcUser implements Serializable {private static final long serialVersionUID = 1L;private String id;private String username;private String password;private String salt;private String name;private String nickname;private String wxUnionid;private String companyId;/*** 头像*/private String userpic;private String utype;private LocalDateTime birthday;private String sex;private String email;private String cellphone;private String qq;/*** 用户状态*/private String status;private LocalDateTime createTime;private LocalDateTime updateTime;}
}
第二步: 在内容管理服务中的查询课程信息接口
中使用工具类获取当前登陆的用户信息
@ApiOperation("根据课程id查询课程基础信息")
@GetMapping("/course/{courseId}")
public CourseBaseInfoDto getCourseBaseById(@PathVariable Long courseId) {SecurityUtil.XcUser user = SecurityUtil.getUser();System.out.println("当前用户身份为:" + user);return courseBaseInfoService.getCourseBaseInfo(courseId);
}
第三步: 启动认证服务、网关、内容管理服务
, 首先访问认证服务生成令牌,然后携带生成的令牌访问内容管理服务的查询课程接口,最后在控制台中查看登陆的用户信息
当前用户身份为:SecurityUtil.XcUser(id=52, username=Kyle, password=null, salt=null, name=Kiki, nickname=null, wxUnionid=null, companyId=1232141425, userpic=null, utype=101002, birthday=null, sex=1, email=null, cellphone=null, qq=null, status=, createTime=2022-09-28T08:32:03, updateTime=null)
相关文章:

04-获取认证的用户身份信息
存储用户信息的方式 获取用户信息的流程 用户提交账号和密码后,DaoAuthenticationProvider调用UserDetailsService接口实现类的loadUserByUsername()方法,该方法可以接收请求参数username的值,然后根据该值查询用户信息,最后将账号,密码,权限封装到UserDetails对象中并返回给…...

二叉树的中序遍历,力扣
目录 题目地址: 题目: 解题方法: 解题分析: 解题思路: 代码实现: 注: 代码实现(递归): 代码实现(迭代): 题目地址…...

shiro1.10版本后-IniSecurityManagerFactory过期失效
1、问题概述? 今天在研究了shiro的新版本shiro1.13.0版本,发现用了很长时间的IniSecurityManagerFactory工厂失效了。 从下图中可以看出,在新版本中IniSecurityManagerFactory被打上了过期线了。 那么问题来了,新版本如何使用呢…...

阿里后端实习二面
阿里后端实习二面 记录面试题目,希望可以帮助到大家 类加载的流程? 类加载分为三个部分:加载、连接、初始化 加载 类的加载主要的职责为将.class文件的二进制字节流读入内存(JDK1.7及之前为JVM内存,JDK1.8及之后为本地内存)&…...

「Kafka」生产者篇
「Kafka」生产者篇 生产者发送消息流程 在消息发送的过程中,涉及到了 两个线程 ——main 线程和Sender 线程。 在 main 线程中创建了 一个 双端队列 RecordAccumulator。 main线程将消息发送给RecordAccumulator,Sender线程不断从 RecordAccumulator…...

C语言实现RSA算法加解密
使用c语言实现了RSA加解密算法,可以加解密文件和字符串。 rsa算法原理 选择两个大素数p和q;计算n p * q;计算φ(n)(p-1)(q-1);选择与φ(n)互素的整数d;由de1 mod φ(n)计算得到e;公钥是(e, n), 私钥是(d, n);假设明…...
如何设计前后端分离的系统架构?
如何将前端页面和后端Java代码进行集成? 将前端页面和后端Java代码进行集成通常需要使用一些特定的工具和技术。以下是一些常见的方法: 使用RESTful API:REST(Representational State Transfer)是一种基于HTTP协议构…...
【强化学习】SARAS代码实现
前言 SARAS,假设环境状态和动作状态都是离散的。利用动作价值矩阵来进行行为的预测。其主要就是利用时序差分的思想,对动作价值矩阵进行更新。 代码实现 import gymnasium as gym import numpy as npclass sarsa():def __init__(self, states_n, acti…...

P1019 [NOIP2000 提高组] 单词接龙 刷题笔记
P1019 [NOIP2000 提高组] 单词接龙 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路来自 大佬 Chardo 的个人中心 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 匹配 : 将 第一个字符串末尾 和第二个字符串第一个开始匹配 如果 j<i这段走完了 flag还没…...

如何实现WinApp的UI自动化测试?
WinApp(WindowsAPP)是运行在Windows操作系统上的应用程序,通常会提供一个可视的界面,用于和用户交互。例如运行在Windows系统上的Microsoft Office、PyCharm、Visual Studio Code、Chrome,都属于WinApp。常见的WinApp&…...
chrome扩展程序开发之在目标页面运行自己的JS
原文地址:https://qdgithub.com/home/index/article/aid/247.html chrome 插件开发的入门介绍,实现利用 chrome 扩展实现在目标网页运行我们的 js 的功能。关于 chrome 扩展的详细内容,可以通过官网了解。 开发工具很简单,记事本…...
NLP项目之语种识别
目录 1. 代码及解读2. 知识点n-grams仅保留最常见的1000个n-grams。意思是n1000 ? 1. 代码及解读 in_f open(data.csv) lines in_f.readlines() in_f.close() dataset [(line.strip()[:-3], line.strip()[-2:]) for line in lines] print(dataset[:5])[(1 december wereld…...
Linux lpr命令教程:如何使用lpr命令打印文件(附案例详解和注意事项)
Linux lpr命令介绍 lpr命令在Unix-like操作系统中用于提交打印任务。如果在命令行中指定了文件名,那么这些文件将被发送到指定的打印机(如果没有指定目的地,则发送到默认目的地)。如果命令行中没有列出文件,lpr将从标…...
浅谈C语言inline关键字
对于C开发者来说,inline是个再熟悉不过的关键字,因为默认的成员函数都是inline,也是常规高校教材中宣扬C的“优势”之一。 但是C语言其实也是支持inline关键字的,而且是很早期的gcc就支持了该关键字。在Linux0.12版本内核代码中也…...

Flink1.17实战教程(第六篇:容错机制)
系列文章目录 Flink1.17实战教程(第一篇:概念、部署、架构) Flink1.17实战教程(第二篇:DataStream API) Flink1.17实战教程(第三篇:时间和窗口) Flink1.17实战教程&…...

OpenCV实战 -- 维生素药片的检测记数
文章目录 检测记数原图经过操作开始进行消除粘连性--形态学变换总结实现方法1. 读取图片:2. 形态学处理:3. 二值化:4. 提取轮廓:5. 轮廓筛选和计数: 分水岭算法:逐行解释在基于距离变换的分水岭算法中&…...
【AI】注意力机制与深度学习模型
目录 一、注意力机制 二、了解发展历程 2.1 早期萌芽: 2.2 真正意义的注意力机制: 2.3 2015 年及以后: 2.4 自注意力与 Transformer: 2.5 BERT 与预训练模型: 三、基本框架 1. 打分函数(Score Fun…...

HTML5和JS实现新年礼花效果
HTML5和JS实现新年礼花效果 2023兔年再见,2024龙年来临了! 祝愿读者朋友们在2024年里,身体健康,心灵愉悦,梦想成真。 下面是用HTML5和JS实现新年礼花效果: 源码如下: <!DOCTYPE html>…...

【owt-server】一些构建项目梳理
【owt-server】清理日志:owt、srs、ffmpeg 【owt】p2p client mfc 工程梳理【m98】webrtc vs2017构建带符号的debug库【OWT】梳理构建的webrtc和owt mfc工程 m79的mfc客户端及owt-client...

Linux shell编程学习笔记38:history命令
目录 0 前言 1 history命令的功能、格式和退出状态1.1 history命令的功能1.2 history命令的格式1.3退出状态2 命令应用实例2.1 history:显示命令历史列表2.2 history -a:将当前会话的命令行历史追加到历史文件~/.bash_history中2.3 history -c…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...

python可视化:俄乌战争时间线关键节点与深层原因
俄乌战争时间线可视化分析:关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一,自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具,系统分析这场战争的时间线、关键节点及其背后的深层原因,全面…...