角色访问控制
通常情况下,我们需要实现“特定资源只能由特定角色访问”的功能。假设我们的系统 有如下两个角色:
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);
}
}