Spring Security系列-Spring Security简单身份认证配置(三)

前言

接着上篇,我们继续配置WebSecurityConfig。上一篇我们配置的是登录相关的参数,接下来再配置一下其它参数。

密码

这里我们得先确定密码的加密方式,默认会使用bcrypt对我们输入的密码进行加密,然后才会比较输入的密码和存放的密码是否一致。
我们需要在WebSecurityConfig文件中,指定加密的方式,后面使用这个加密对象,对我们的密码进行加密。

@Bean
public PasswordEncoder passwordEncoder() {
    // 使用默认bcrypt的方式对密码进行加密
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    // 不进行密码加密
    // return NoOpPasswordEncoder.getInstance();
}

用户

用户密码除了第一篇使用application.yml文件配置的方式外,还可以使用代码的方式

  1. InMemory,使用HashMap存放和维护User信息
  2. JDBC,通过数据库来存放和维护User信息
  3. LDAP,通过LDAP来
  4. 自定义
    4-1. 继承AuthenticationProvider,自定义获取User信息
    4-2. 继承UserDetailsService接口,自定义获取User信息

InMemory

在WebSecurityConfig文件中,使用InMemory的方式配置了两个用户,此处使用了上面注入的加密对象,对密码进行了加密。

@Autowired
PasswordEncoder passwordEncoder;
    
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("tester")
            .password(passwordEncoder.encode("123456"))
            .authorities("tester")
            .and()
            .withUser("user")
            .password(passwordEncoder.encode("123456"))
            .authorities("user");
}

访问http://locahost:8080/login就可以使用上面我们配置的两个用户登录访问了。

JDBC

这次我们使用JDBC方式来读取数据库中的用户信息,进行身份认证。

引用jdbc和mysql包

数据库使用的mysql5.6版本

<!--数据库-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.13</version>
</dependency>

准备数据库和表

Spring Security为我们准备了数据库脚本,jar包中的org/springframework/security/core/userdetails/jdbc/users.ddl文件。
在这里插入图片描述在项目启动时就会运行初始化脚本,但是我使用的数据库mysql5.6,不支持varchar_ignorecase类型。因此需要自己准备好数据库,并运行下面的sql脚本。

create table users(username varchar(50) not null primary key,password varchar(500) not null,enabled boolean not null);
create table authorities (username varchar(50) not null,authority varchar(50) not null,constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority);

配置WebSecurityConfig

withDefaultSchema方法会运行数据表初始化脚本,前提是你的数据库支持varchar_ignorecase字段类型。这里我同样添加了两个用户。

@Autowired
DataSource dataSource;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    auth.jdbcAuthentication()
            .dataSource(dataSource)
            // 下面的方法会运行数据表初始化脚本,前提是你的数据库支持varchar_ignorecase字段类型
            // .withDefaultSchema()
	        //使用自定义sql查询用户信息
	        .usersByUsernameQuery("select username,password,enabled from users " + "where username = ?")
            .withUser("tester")
            .password(passwordEncoder.encode("123456"))
            .authorities("tester")
            .and()
            .withUser("user")
            .password(passwordEncoder.encode("123456"))
            .authorities("tester");
}

在项目启动的时候,我们会发现刚刚创建的数据表中已经有两条用户记录了。加密后的密码有{bcrypt}的前缀,说明是使用bcrypt方式进行加密
在这里插入图片描述

测试

访问http://locahost:8080/login就可以使用上面我们配置的两个用户登录访问了。

自定义AuthenticationProvider

下面是写了一个继承AuthenticationProvider的匿名类。support方法用来判断是否验证,authenticate方法用来验证。如果用户名密码正确,就返回一个UsernamePasswordAuthenticationToken带有用户的认证信息。此处的用户密码是写死的,如果是正式项目,就可以从数据库中获取用户信息。

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(new AuthenticationProvider() {
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            String username = authentication.getName();
            if (authentication.getCredentials() == null)
                throw new BadCredentialsException("Bad credentials");
            String password = authentication.getCredentials().toString();
            if( "user".equals(username) && "123456".equals(password)) {
                UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
                        authentication.getPrincipal(), authentication.getCredentials(),
                        authentication.getAuthorities());
                result.setDetails(authentication.getDetails());
                return result;
            }

            throw new UsernameNotFoundException("用户或密码错误");
        }

        @Override
        public boolean supports(Class<?> authentication) {
            return (UsernamePasswordAuthenticationToken.class
                    .isAssignableFrom(authentication));
        }
    });
}

自定义UserDetailsService

和上面的AuthenticationProvider方式不同,这里使用返回的是一个UserDetails。这个UserDetails是给DaoAuthenticationProvider类用的,它会去比较登录时填写的User和这里UserDetails返回的User,进行用户名和密码的比较。如果相同,那么就通过验证。
DaoAuthenticationProvider从名字上看出,它是继承自AuthenticationProvider,有兴趣的同学可以看看它的源代码。

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(new UserDetailsService() {
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            if ("user".equals(username)) {
                return new User(
                        "user",
                        passwordEncoder.encode("123456"),
                        Collections.singletonList(new SimpleGrantedAuthority("user")
                        ));
            }
            return null;
        }
    });
}

结语

本篇使用了多种不同的方式来判断用户登录时的身份认证,至于LDAP方式,我这边没有使用和测试,基本原理都差不多。对于正式项目,大部分情况会使用自定义AuthenticationProvider或者UserDetailsService的方式,搭配数据库和redis来进行身份认证,可以更加灵活的面对变化的需求。

源代码

github项目地址https://github.com/camellibby/security-demo

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值