1 Star 1 Fork 552

衣小白 / CS-Wiki

forked from 小牛肉 / cs-wiki 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
3-基于内存的认证和授权.md 6.33 KB
一键复制 编辑 原始数据 按行查看 历史
小牛肉 提交于 2021-07-11 21:36 . 🥽 更新目录结构

⌨ 基于内存的认证和授权


1. 基于内存的认证信息

上节我们简单体验了下Spring Security,但是现在只能有一个用户信息,我们这里希望可以配置多个账号信息,本节主要讲解下如何在内存中配置认证信息。

① 创建配置类

定义一个配置类 WebSecurityConfig,继承 WebSecurityConfigurerAdapter,如下代码:

@Configuration
@EnableWebSecurity // 开启Spring Security的功能
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    // 认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /*
         * 配置为从内存中进行加载认证信息.
         * 这里配置了两个用户 admin和user
         */
        auth.inMemoryAuthentication().withUser("admin").password("123456").roles();
        auth.inMemoryAuthentication().withUser("user").password("123456").roles();
    }
}

🚨 如果是 5.x 之前的版本的话,那么到这里启动的话,就可以正常访问了,但是如果是 5.x 的版本的话,可以正常启动,但是在登录页面输入账号进行访问的话,会报如下错误:

java.lang.IllegalArgumentException:There is no PasswordEncoder mapped for the id "null"

这是因为 Spring Security 5.0中新增了多种加密方式,也改变了密码的格式。我们需要指定加密方式 👇

② 密码加密

Ⅰ 方式 1:通过AuthenticationManagerBuilder指定

AuthenticationManagerBuilder 的方法中就可以指定加密方式了,如下代码:

auth.inMemoryAuthentication()
    .passwordEncoder(new BCryptPasswordEncoder())
    .withUser("admin")
    .password(new BCryptPasswordEncoder().encode("123456"))
    .roles();

auth.inMemoryAuthentication()
    .passwordEncoder(new BCryptPasswordEncoder())
    .withUser("user")
    .password(new BCryptPasswordEncoder().encode("123456"))
    .roles();

Bcrypt: bcrypt是一种跨平台的文件加密工具。bcrypt 使用的是布鲁斯·施内尔在1993年发布的 Blowfish 加密算法。由它加密的文件可在所有支持的操作系统和处理器上进行转移。它的口令必须是8至56个字符,并将在内部被转化为448位的密钥。

Ⅱ 方式 2:通过@Bean注入指定PasswordEncoder

WebSecurityConfig 配置类中,通过 @Bean 注入 PasswordEncoder 具体的实现类,如下代码:

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

加入这个之后,需要修改密码加密:

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

        /*
         * 配置为从内存中进行加载认证信息.
         * 这里配置了两个用户 admin和user
         */
        auth.inMemoryAuthentication()
            .withUser("admin")
            .password(passwordEncoder().encode("123456"))
            .roles();

        auth.inMemoryAuthentication()
            .withUser("user")
            .password(passwordEncoder().encode("123456"))
            .roles();
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

对于上面的两种方式,推荐使用第二种方式,这种方式一方面更容易理解,另外代码扩展性更强。

2. 基于内存的用户授权

上面我们基于内存的方式,构建了两个账号 admin 和 user,对于这两个账号在实际项目中会有不同的角色,比如管理员角色和普通用户角色,对于不同的角色,那么允许访问的方法会不一样。

① 为用户配置角色

通过 AuthenticationManagerBuilderroles() 方法分配角色:

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

    /*
     * 配置为从内存中进行加载认证信息.
     * 这里配置了两个用户 admin和user
     */
    auth.inMemoryAuthentication()
        .withUser("admin")
        .password(passwordEncoder().encode("123456"))
        .roles("admin");

    auth.inMemoryAuthentication()
        .withUser("user")
        .password(passwordEncoder().encode("123456"))
        .roles("normal");
}

② 开启 Spring 方法级安全

想要开启 Spring 方法级安全,你需要在已经添加了 @Configuration 注解的类上再添加 @EnableGlobalMethodSecurity 注解:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
  • prePostEnabled :决定 Spring Security 的前注解是否可用 [@PreAuthorize,@PostAuthorize,..]

    即只有添加了@EnableGlobalMethodSecurity(prePostEnabled=true) 之后,@PreAuthorize("hasAnyRole('admin')") 才能生效。

  • secureEnabled : 决定是否 Spring Security 的保障注解 [@Secured] 是否可用。

  • jsr250Enabled :决定 JSR-250 annotations 注解[@RolesAllowed..] 是否可用。

③ 配置方法级拥有的角色

我们在 HelloController 添加两个方法,使用注解 @PreAuthorize 指定访问该方法需要的角色:

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        return "Hello,Spring Security";
    }

    @RequestMapping("/helloAdmin")
    @PreAuthorize("hasAnyRole('admin')") // 只允许角色 admin 访问
    public String helloAdmin() {
        return "Hello,admin";
    }

    @RequestMapping("/helloUser")
    @PreAuthorize("hasAnyRole('admin','normal')") // 允许角色 admin 和 normal 访问
    public String helloUser() {
        return "Hello,user";
    }
}

④ 测试

访问如下地址:http://127.0.0.1:8080/helloUser,跳转到登录页面,输入账号 user/123456,成功登录之后,会看到返回信息:Hello,user

然后在输入另外一个地址:http://127.0.0.1:8080/helloAdmin,这时候会看到403的报错,因为该用户没有权限访问该方法

重新启动应用程序,输入 admin/123456 账号进行测试,都能正常访问。

📚 References

Java
1
https://gitee.com/yihaibin/CS-Wiki.git
git@gitee.com:yihaibin/CS-Wiki.git
yihaibin
CS-Wiki
CS-Wiki
master

搜索帮助