在第1节中我们已经将SpringBoot及Security整合到了一起,并且通过默认的用户名user与随机生成的密码成功登录。
下面我们要做的是使用自己配置的用户名进行登录
1、创建配置类
创建一个叫SecurityConfig配置类,此类继承自Security的WebSecurityConfigurerAdapter,并使用了3个注解。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
})
.withUser("LeoLee").password( "123456").roles("USER")
.and()
.withUser("KimQu").password( "123456").roles("ADMIN");
}
}
重启项目,发现我们已经可以用配置好的两个用户名【LeoLee】与【KimQu】使用相应的密码进行登录了。
2、解读代码
2.1 注解
@Configuration 表明这个类是一个配置类,可替换xml配置文件。
@EnableWebSecurity 是Spring Security用于启用Web安全的注解。典型的用法是该注解用在某个Web安全配置类上(实现了接口WebSecurityConfigurer或者继承自WebSecurityConfigurerAdapter) 此注解一般用于控制Spring Security是否使用调试模式(通过注解属性debug指定),缺省为false,表示缺省不使用调试模式。
@EnableGlobalMethodSecurity(prePostEnabled = true) 默认情况下Spring Security是禁用注解的,要想开启注解, 需要在继承WebSecurityConfigurerAdapter的类上开启此注解。
2.2 WebSecurityConfigurerAdapter
表明此类继续自Security的WebSecurityConfigurerAdapter类
2.3 密码加密方式
可以自定义加密方式,也可以使用Security推荐的BCryptPasswordEncoder,这里使用的是自定义的加密方式
2.4 自定义的加密和匹配方式
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
加密方式,看代码能看出来就是没加密,你给我啥,我返回啥
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
匹配方式,由于没有加密,所以匹配的时候自然也是无需加密或解密了,或者你可以调皮下,直接返回个true~
2.5 用户名/密码/角色
这块儿没啥可说的,中间使用and相连接就可以。顶多可以说一说的就是密码这一块,【password( "123456")】中的字串,其实就是上面matches方法中的【s】字串。也就是说每次在匹配的方法中,实际上都是在用【password("")】中的字串来匹配你的输入项。
3、自定义加密方式
3.1 传统的MD5加密
3.1.1先在POM中加入jar包
在properties中加入,如下语句:
<commoncodec.version>1.6</commoncodec.version>
在dependencies中加入,如下语句:
<!-- commons-codec是Apache开源组织提供的用于摘要运算、编码解码的包 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commoncodec.version}</version>
</dependency>
3.1.2修改SecurityConfig类
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
// 对密码进行 md5 加密
String pwd = DigestUtils.md5DigestAsHex( charSequence.toString().getBytes() );
System.out.println("encode:charSequence:" +charSequence);
System.out.println("encode:pwd:" +pwd);
return pwd;
}
@Override
public boolean matches(CharSequence charSequence, String s) {
String encode = encode(charSequence.toString());
System.out.println("matches:charSequence:" +charSequence.toString());
System.out.println("matches:encode:" +encode);
System.out.println("matches:s:" +s);
return s.equals( encode );
}
})
.withUser("LeoLee").password( "e10adc3949ba59abbe56e057f20f883e").roles("USER")
.and()
.withUser("KimQu").password( "e10adc3949ba59abbe56e057f20f883e").roles("ADMIN");
}
}
其中【password( "e10adc3949ba59abbe56e057f20f883e")】中的【e10adc3949ba59abbe56e057f20f883e】为对【123456】加密后的MD5摘要,重启系统仍然使用【123456】进行登录~
其实,上面的代码只是为了输出查看,如果在真实环境中(当然,我觉得也不会在真实环境中将用户信息写在配置类中),可以写为如下式样:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
// 对密码进行 md5 加密
return DigestUtils.md5DigestAsHex( charSequence.toString().getBytes() );
}
@Override
public boolean matches(CharSequence charSequence, String s) {
// 与加密后的字串做匹配
return s.equals( encode(charSequence.toString()) );
}
})
.withUser("LeoLee").password( "e10adc3949ba59abbe56e057f20f883e").roles("USER")
.and()
.withUser("KimQu").password( "e10adc3949ba59abbe56e057f20f883e").roles("ADMIN");
}
}
3.2 Security推荐的加密方式BCryptPasswordEncoder
将SecurityConfig类代码修改如下:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("LeoLee").password( "$2a$10$uDQWkXJHI6gEURvnZmpareZYB53Xbe4p6twWITQU/PYZWu95wEI7O").roles("USER")
.and()
.withUser("KimQu").password( "$2a$10$S8De83OCGxmVX3Q8nPs.Ou3Pfl6ovzVJrRVAVAXWU6xaRZRopt/qq").roles("ADMIN");
}
}
然后对【LeoLee】与【KimQu】使用同样的【123456】进行登录,登录成功。
然而……,这时有细心的同学可能就发现了,这个【LeoLee】与【KimQu】在【password("")】中的值实际上是不一样儿的,可为啥两个人依然可以使用相同的密码进行登录呢?而且我们在开发中一般都是将用户信息写在数据库中的,不能像这样写在配置类中啊。莫慌,有老夫呢~
先看看我们目前的项目结构
与上一节一样,红色框中的是这一节我们修改过的文件~
接下来就和你聊一聊Security是如何使用数据库来进行用户鉴权的