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

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

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对象的更多方法如下表:

45.png


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对象时填入数据。

46.png


在Security中,角色和权限共用GrantedAuthority接口,唯一的不同角色就是多了个前缀"ROLE_",而且它没有Shiro的那种从属关系,即一个角色包含哪些权限等等。在Security看来角色和权限时一样的,它认证的时候,把所有权限(角色、权限)都取出来,而不是分开验证。

所以,在Security提供的UserDetailsService默认实现JdbcDaoImpl中,角色和权限都存储在auhtorities表中。而不是像Shiro那样,角色有个roles表,权限有个permissions表。以及相关的管理表等等。

GrantedAuthority接口的默认实现SimpleGrantedAuthority


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

47.png


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

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

48.png


49.png

但是前面说到了,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

目录
相关文章
|
Java
SpringBoot 整合JWT实现基于自定义注解的-登录请求验证拦截(保姆级教学,附:源码)2
SpringBoot 整合JWT实现基于自定义注解的-登录请求验证拦截
195 0
|
5月前
SpringBoot_JWT用户登录
SpringBoot_JWT用户登录
44 0
|
存储 安全 Java
Spring Security Oauth2 之 密码模式请求/oauth/token 解析
前言 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger 种一棵树最好的时间是十年前,其次是现在
1435 0
Shiro用户鉴权框架 子线程获取不到用户信息问题解决
Shiro用户鉴权框架 子线程获取不到用户信息问题解决
|
5月前
|
存储 缓存 NoSQL
【视频+源码】登录鉴权的三种方式:token、jwt、session实战分享
【视频+源码】登录鉴权的三种方式:token、jwt、session实战分享
117 1
|
12月前
|
存储 NoSQL Java
SpringBoot自定义实现类似jwt权限验证效果
SpringBoot自定义实现类似jwt权限验证效果
74 0
|
安全 Java 数据库
Sping Security-3-动态认证用户信息
Sping Security-3-动态认证用户信息
126 1
|
存储 JSON 安全
JWT验证用户信息功能与OAuth2协议
JWT验证用户信息功能与OAuth2协议
105 0
|
SQL 安全 Java
SpringBoot 整合SpringSecurity示例实现前后分离权限注解+JWT登录认证
SpringSecurity是一个用于Java 企业级应用程序的安全框架,主要包含用户认证和用户授权两个方面.相比较Shiro而言,Security功能更加的强大,它可以很容易地扩展以满足更多安全控制方面的需求,但也相对它的学习成本会更高,两种框架各有利弊.实际开发中还是要根据业务和项目的需求来决定使用哪一种.
SpringBoot 整合SpringSecurity示例实现前后分离权限注解+JWT登录认证
|
算法 Java 数据库
一张流程图带你学会SpringBoot结合JWT实现登录功能(二)
一张流程图带你学会SpringBoot结合JWT实现登录功能
141 0