首页 > 其他分享 >OAuth2.0实战(三)用户信息加载

OAuth2.0实战(三)用户信息加载

时间:2022-12-07 20:03:26浏览次数:50  
标签:实战 password OAuth2.0 角色 用户 ROLE authorities 权限 加载


Spring Security内置了三种用户存储方式:
1、基于内存
2、基于数据库查询语句
3、自定义UserDetailsService服务来获取
这里的用户存储指的是,从哪里获取用户的信息

1、基于内存存储用户信息

在WebSecurityConfig类中配置:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.inMemoryAuthentication()
.withUser("user").password("{noop}123456").roles("USER")
.and()
.withUser("admin").password("{noop}123456").roles("USER","ADMIN");
}

withUser()方法返回的是UserDetailsManagerConfigurer.UserDetailsBuilder,这个对象提供了多个进一步配置用户的方法,如上面的为用户设置密码的password()方法、授予用户多个角色权限的roles()方法。UserDetailsManagerConfigurer.UserDetailsBuilder对象的更多方法如下表:

OAuth2.0实战(三)用户信息加载_加载

roles()方法是authorities()方法的简写形式。roles()方法所给定的值都会添加一个“ROLE_”前缀,并将其作为权限授予给用户。如下的配置和上面的等价:

auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").authorities("ROLE_USER")
.and()
.withUser("admin").password("{noop}password").authorities("ROLE_USER","ROLE_ADMIN");

2.基于数据库库sql查询语句

auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username,password,true from Spitter where username=?")
.authoritiesByUsernameQuery("select username,'ROLE_USER' from Spitter where username=?");

3、自定义UserDetailsService服务来获取用户信息

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(MyUserDetailsService());
}

UserDetailsService在身份认证中的作用

Spring Security中进行身份验证的是AuthenticationManager接口,ProviderManager是它的一个默认实现,但它并不用来处理身份认证,而是委托给配置好的AuthenticationProvider,每个AuthenticationProvider会轮流检查身份认证。检查后或者返回Authentication对象或者抛出异常。

验证身份就是加载响应的UserDetails,看看是否和用户输入的账号、密码、权限等信息匹配。此步骤由实现AuthenticationProvider的DaoAuthenticationProvider(它利用UserDetailsService验证用户名、密码和授权)处理。包含 GrantedAuthority 的 UserDetails对象在构建 Authentication对象时填入数据。

OAuth2.0实战(三)用户信息加载_ide_02

在Security中,角色和权限共用GrantedAuthority接口,唯一的不同角色就是多了个前缀"ROLE_",而且它没有Shiro的那种从属关系,即一个角色包含哪些权限等等。在Security看来角色和权限时一样的,它认证的时候,把所有权限(角色、权限)都取出来,而不是分开验证。
所以,在Security提供的UserDetailsService默认实现JdbcDaoImpl中,角色和权限都存储在auhtorities表中。而不是像Shiro那样,角色有个roles表,权限有个permissions表。以及相关的管理表等等。
GrantedAuthority接口的默认实现SimpleGrantedAuthority

注意,在构建SimpleGrantedAuthority对象的时候,它没有添加任何前缀。所以表示"角色"的权限,在数据库中就带有"ROLE_"前缀了。所以authorities表中的视图可能是这样的。

OAuth2.0实战(三)用户信息加载_UserDetailsService_03

角色和权限能否分开存储?角色能不能不带"ROLE_"前缀

当然可以分开存储,你可以定义两张表,一张存角色,一张存权限。但是你自定义UserDetailsService的时候,需要保证把这两张表的数据都取出来,放到UserDails的权限集合中。当然你数据库中存储的角色也可以不带"ROLE_"前缀,就像这样。

OAuth2.0实战(三)用户信息加载_OAuth2.0_04


OAuth2.0实战(三)用户信息加载_ide_05

但是前面说到了,Security才不管你是角色,还是权限。它只比对字符串
比如它有个表达式hasRole(“ADMIN”)。那它实际上查询的是用户权限集合中是否存在字符串"ROLE_ADMIN"。如果你从角色表中取出用户所拥有的角色时不加上"ROLE_"前缀,那验证的时候就匹配不上了。
所以角色信息存储的时候可以没有"ROLE_"前缀,但是包装成GrantedAuthority对象的时候必须要有。

// 设置添加用户信息,正常应该从数据库中读取

@Bean
UserDetailsService userDetailsService() {
//内存保存
/* InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
userDetailsService.createUser(User.withUsername("user1").password("{noop}123456")
.authorities("ROLE_USER").build());
userDetailsService.createUser(User.withUsername("user2").password("{noop}1234567")
.authorities("ROLE_USER").build());*/

//数据库加载
UserDetailsService userDetailsService = new UserDetailsService(){
//根据username加载用户基本信息,权限信息,角色信息 校验可以在自定义的daoAuhthenticationProvider中做
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
AuthUser authUser = authUserMapper.selectByUsername(username);
if (authUser == null) {
throw new UsernameNotFoundException("账户不存在");
}
// MyUserDetails myUserDetails = new MyUserDetails(authUser) ;
//校验 这里只加载用户信息,尽量不要做校验 校验可以在自定义的daoAuhthenticationProvider中做
/* if (myUserDetails==null || myUserDetails.getAuthorities().isEmpty()) {
throw new UsernameNotFoundException("用户未分配任何权限");
}*/
return new User(authUser.getUsername(),authUser.getPassword(),this.getAuthorities(authUser));
}


public Collection<GrantedAuthority> getAuthorities(AuthUser authUser) {
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
//查用户角色
List<AuthRole> authRoles = authRoleMapper.selectByUserId(authUser.getId());
//查用户权限
List<AuthPermission> authPermissions = authPermissionMapper.selectByRoles(authRoles);

if (authRoles != null)
{
//角色权限
Set<String> roleStrs = authRoles.stream().map(AuthRole::getRoleName).collect(Collectors.toSet());
for (String code : roleStrs) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(code);
authorities.add(authority);
}
//方法权限
Set<String> authStrs = authPermissions.stream().map(AuthPermission::getCode).collect(Collectors.toSet());
for (String code : authStrs) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(code);
authorities.add(authority);
}
}
return authorities;
}
};
return userDetailsService;
}

说明:
这里的返回结果User就是UserDetails接口的实现类:

public User(String username, String password, Collection<? extends GrantedAuthority> authorities) {
this(username, password, true, true, true, true, authorities);
}

构造方案非常简单:
username 用户名
password 密码
authorities 权限

总结:
1、本章介绍了OAuth2.0用户信息可以有2种存储方式,一种是存放在内存中,一般只会在测试时使用;一种是基于数据库的持久化存储。

三种加载用户信息的方式:

  • 直接基于内存中的用户信息去进行认证inMemoryAuthentication
  • 采用sql语句从数据库加载用户信息
  • 继承UserDetailsService方法,加载用户信息,推荐使用这种方法,最灵活通用。

github源码:
​ https://github.com/StarlightWANLI/oauth2.git​​

如果你还有其他OAuth2.0认证方面的想了解的内容,可以在底下评论留言。我会尽力抽空调研下。

最后,如果我写的文章对您能有些许帮助,请帮忙点赞、关注。


标签:实战,password,OAuth2.0,角色,用户,ROLE,authorities,权限,加载
From: https://blog.51cto.com/u_15905482/5920001

相关文章

  • k8s授权管理介绍与实战(RBAC)
    授权管理授权发生在认证成功之后,通过认证就可以知道请求用户是谁,然后Kubernetes会根据事先定义的授权策略来决定用户是否有权限访问,这个过程就称为授权。每个发送到ApiS......
  • 云数据库FinOps实战复盘
    历时三个多月的HBase成本优化项目按照预期交付了,HBase云数据库月度成本下降了32.5%,超出预期达成目标。我们对本次HBase成本优化项目进行深度复盘,并进一步尝试总结云数据库......
  • gin框架项目实战系列汇总
    最近打算整理重构项目的一些使用心得,打算做以下系列更新:gin-注册路由gin-中间件gin-http/https配置gin-配置初始化-vipergin-错误定义gin-统一响应responsegin-zap......
  • Python爬虫实战,requests模块,Python抓取虎牙直播美女封面图片
    前言今天给大家的介绍Python爬取海量美女图片并保存本地。开发工具Python版本:3.8相关模块:requests模块multiprocessing模块urllib模块json模块环境搭建安装Pyth......
  • cesium加载倾斜摄影,添加billboard并注册点击事件
       完整示例代码如下:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>天地图</title><!--引用cesium的js和css,天地图的扩展js--......
  • vulnhub靶场渗透实战13-driftingblues3
    ​靶机下载地址:https://download.vulnhub.com/driftingblues/driftingblues3.ovavbox导入,网络模式桥接,靶机模式为简单。一:信息收集1;直接老样子吧,arp主机发现之后,nmap扫......
  • 瀑布流布局 不到30行代码实现(JavaScript + absolute)支持懒加载
    @目录前言一、使用css实现瀑布流布局1.flex布局2.column-count多栏布局3.grid网格布局二、结合JavaScript的瀑布流布局实现1.推荐原因2.实现步骤a.初步实现:结合JavaSc......
  • GDIplus的初次接触--加载并显示常用格式图片
     在没有接触Gdiplus之前,在vc中绘制图片,通常加载一张位图,然后进行贴图。对于现在多种多样的图片格式,之前的GDI并不支持(应该是这样的,呵呵)。而使用Gdiplus则可以选择多种图片......
  • Git实战(五)| 让工作更高效,搞定Git的分支管理
    上一篇讲到Git的分支管理实操,在线合并和本地合并都进行了实操。毕竟:光说不练是假把式。而只练不整理,只能是傻把式了。分支管理到底如何进行管理呢?先以GitLab上的一张经典......
  • DataX源码分配三:配置加载
    【1】入口ConfigParser::parse   方法参数为命令行中指定的作业配置文件。 【2】配置保存方式datax使用Configuration类保存作业配置,保存方式简单粗暴。Config......