Spring Security三

Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的实际标准。Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring Security的真正强大之处在于可以轻松扩展以满足自定义要求

授权
所谓的授权,就是用户如果要访问某一个资源,我们要去检查用户是否具备这样的权限,如果具备就允许访问,如果不具备,则不允许访问。

准备测试用户
因为现在还没有连接数据库,所以测试用户还是基于内存来配置。

基于内存配置测试用户,有两种方式,第一种就配置方式,如下:


        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("yuzb")
                    .password("123").roles("admin")
                    .and().
                    withUser("yu")
                    .password("123").roles("user");
        }

由于 Spring Security 支持多种数据源,例如内存、数据库、LDAP 等,这些不同来源的数据被共同封装成了一个 UserDetailService 接口,任何实现了该接口的对象都可以作为认证数据源。

因此还可以通过重写 WebSecurityConfigurerAdapter 中的 userDetailsService 方法来提供一个 UserDetailService 实例进而配置多个用户:

 @Bean
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("a").password("123").roles("admin").build());
        manager.createUser(User.withUsername("b").password("123").roles("user").build());
        return manager;
    }

以上任选其一

准备测试接口

@RestController
public class SecurityController {  @GetMapping("/hello")
public String hello() {
    return "hello";
}

    @GetMapping("/admin/hello")
    public String admin() {
        return "admin";
    }

    @GetMapping("/user/hello")
    public String user() {
        return "user";
    }
}

这三个测试接口规划是这样的:

  • /hello 是任何人都可以访问的接口
  • /admin/hello 是具有 admin 身份的人才能访问的接口
  • /user/hello 是具有 user 身份的人才能访问的接口
  • 所有 user 能够访问的资源,admin 都能够访问
    注意第四条规范意味着所有具备 admin 身份的人自动具备 user 身份。

配置
接下来来配置权限的拦截规则,在 Spring Security 的 configure(HttpSecurity http) 方法中,代码如下:

 http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")
                .antMatchers("/user/**").hasRole("user")
                .anyRequest().authenticated()
                .and()

这里的匹配规则采用了 Ant 风格的路径匹配符,Ant 风格的路径匹配符在 Spring 家族中使用非常广泛,它的匹配规则也非常简单:
在这里插入图片描述
上面配置的含义是:

  • 如果请求路径满足 /admin/** 格式,则用户需要具备 admin 角色。
  • 如果请求路径满足 /user/** 格式,则用户需要具备 user 角色。
  • 剩余的其他格式的请求路径,只需要认证(登录)后就可以访问。
    注意代码中配置的三条规则的顺序非常重要,和 Shiro 类似,Spring Security 在匹配的时候也是按照从上往下的顺序来匹配,一旦匹配到了就不继续匹配了,「所以拦截规则的顺序不能写错」。

另一方面,如果强制将 anyRequest 配置在 antMatchers 前面,像下面这样:

http.authorizeRequests()
        .anyRequest().authenticated()
        .antMatchers("/admin/**").hasRole("admin")
        .antMatchers("/user/**").hasRole("user")
        .and()

此时项目在启动的时候,就会报错,会提示不能在 anyRequest 之后添加 antMatchers:

 nested exception is java.lang.IllegalStateException: Can't configure antMatchers after anyRequest

启动项目,以user角色访问

  • http://localhost:8080/hello因为登录后就可以访问,这个接口访问成功。
  • http://localhost:8080/admin/hello需要 admin 身份,所以访问失败。
  • http://localhost:8080/user/hello访需要 user 身份,所以访问成功。

角色继承
所有 user 能够访问的资源,admin 都能够访问,很明显目前的代码还不具备这样的功能。

要实现所有 user 能够访问的资源,admin 都能够访问,这涉及到另外一个知识点,叫做角色继承。

这在实际开发中非常有用。

上级可能具备下级的所有权限,如果使用角色继承,这个功能就很好实现,只需要在 SecurityConfig 中添加如下代码来配置角色继承关系即可:

   @Bean
    RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
        hierarchy.setHierarchy("ROLE_admin > ROLE_user");
        return hierarchy;
    }

注意,在配置时,需要给角色手动加上 ROLE_ 前缀。上面的配置表示 ROLE_admin 自动具备 ROLE_user 的权限。
访问http://localhost:8080/user/hello,发现admin角色可以访问user’角色权限的接口

将用户数据存入数据库

加入依赖

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

用户配置

			 @Autowired
    DataSource dataSource;
    @Bean
    protected UserDetailsService userDetailsService() {
//        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
        manager.setDataSource(dataSource);
        if (!manager.userExists("a")) {
            manager.createUser(User.withUsername("a").password("123").roles("admin").build());
        }
        if (!manager.userExists("b")) {
            manager.createUser(User.withUsername("b").password("123").roles("user").build());
        }
        return manager;
    }

数据库配置

spring.datasource.username=root
spring.datasource.password=yuzb
spring.datasource.url=jdbc:mysql:///yuzbadmin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

执行数据库脚本

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);
  • users 表中保存用户的基本信息,包括用户名、用户密码以及账户是否可用。
  • authorities 中保存了用户的角色。
  • authorities 和 users 通过 username 关联起来。

启动项目查看数据库
在这里插入图片描述
在这里插入图片描述
这样就能正常访问了

修改数据库将用户的 enabled 属性设置为 false,表示禁用该账户,此时再使用该账户登录就会登录失败。
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值