角色访问控制

      通常情况下,我们需要实现“特定资源只能由特定角色访问”的功能。假设我们的系统 有如下两个角色:

ADMIN 可以访问所有资源  
USER 只能访问特定资源

      现在我们给系统增加“/user/**”接口代表用户信息方面的资源(USER 可以访问);增加"/admin/**"接口代表管理员方面的资源(USER 不能访问),代码如下:
/*用户信息方面的资源*/ 
@RestController 
public class UserController { 
        @RequestMapping("/user/hello") 
        public String hello() { 
              return "user,Hello !"; 
     } 
}
/*管理员方面的资源*/ 
@RestController 
public class AdminController { 
         @RequestMapping("/admin/hello") 
          public String hello() { 
                  return "admin,Hello !"; 
    } 
}
在实际开发中,我们的用户和角色是保存在数据库中的

为了方便演示,我们来创建两个存放于内存的用户和角色。我们可以自定义类并集成 WebSecurityConfigurerAdapter 进而实现 Spring Security 的更多配置,如下代码
@Configuration 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
       /*不对密码进行加密*/ 
       @Bean 
       PasswordEncoder passwordEncoder(){ 
               return NoOpPasswordEncoder.getInstance(); 
       }
       @Override 
       protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
              auth.inMemoryAuthentication() 
                              /*管理员用户 具备 ADMIN 和 USER 角色*/ 
                              .withUser("admin").password("admin").roles("ADMIN", "USER") 
                              .and() 
                              /*普通用户*/ 
                              .withUser("beixi").password("beixi").roles("USER"); 
       }
       @Override 
       protected void configure(HttpSecurity http) throws Exception {
              http 
                            .authorizeRequests() 
                            /*普通用户访问的 url*/ 
                            .antMatchers("/user/**").hasRole("USER") 
                            /*管理员用户访问的 url*/ 
                            .antMatchers("/admin/**").hasRole("ADMIN") 
                            .anyRequest().authenticated() //其他多有路径都必须认证 
                            .and() 
                            .formLogin() 
                            .loginProcessingUrl("/login") 
                            .permitAll() //访问/login 接口不需要进行身份认证了,防止重定向死循环 
                            .and() 
                            .csrf().disable(); //关闭 csrf 
     } 
}
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.security</groupId>
    <artifactId>springsecurity</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <!-- 声明项目配置依赖编码格式为 utf-8 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <fastjson.version>1.2.24</fastjson.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
server.port=8087

spring.security.user.name=admin
spring.security.user.password=123456
package com.tszr.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String home() {
        return "Hello ,spring security!";
    }
}
package com.tszr.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @RequestMapping("/user/hello")
    public String hello() {
        return "user,Hello !";
    }
}
package com.tszr.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AdminController {
    @RequestMapping("/admin/hello")
    public String hello() {
        return "admin,Hello !";
    }
}
package com.tszr.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@SuppressWarnings("deprecation")
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /* 不对密码进行加密 */
    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                /* 管理员用户 具备ADMIN和USER角色 */
                .withUser("admin").password("admin").roles("ADMIN", "USER").and()
                /* 普通用户 */
                .withUser("beixi").password("beixi").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                /* 普通用户访问的url */
                .antMatchers("/user/**").hasRole("USER")
                /* 管理员用户访问的url */
                .antMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated() // 其他多有路径都必须认证
                .and().formLogin().loginProcessingUrl("/login").permitAll() // 访问“/login”接口不需要进行身份认证了,防止重定向死循环
                .and().csrf().disable(); // 关闭csrf
    }
}
package com.tszr.application;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}