(1). 概述
在这里先对Spring Security进行一个简单的入门,入门案例的要求是,判断用户是否具备有URL访问的权限.
(2). 项目目录结构如下
lixin@lixin GitWorkspace % tree spring-security-example 
spring-security-example
├── README.md
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── help
│   │   │       └── lixin
│   │   │           └── security
│   │   │               └── example
│   │   │                   ├── Application.java
│   │   │                   ├── access
│   │   │                   │   └── PermissionVaidator.java
│   │   │                   ├── config
│   │   │                   │   └── WebSecurityConfig.java
│   │   │                   ├── controller
│   │   │                   │   └── HelloController.java
│   │   │                   └── userdetails
│   │   │                       └── DefaultUserDetailsService.java
│   │   └── resources
│   │       └── static
│   │           └── login.html
│   └── test
└── target
(3). WebSecurityConfig
package help.lixin.security.example.config;
import help.lixin.security.example.userdetails.DefaultUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        // 注意:当你发现调用不了UserDetailsService的时候,要注意关闭csrf
        http.formLogin()
                // 登录成功后,必须要是POST请求
                // .successForwardUrl("/main.html")
                // 登录页面
                .loginPage("/login.html")
                // 登录处理URL(Filter[UsernamePasswordAuthenticationFilter])
                .loginProcessingUrl("/login");
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests();
        expressionInterceptUrlRegistry
                // 允许/login.html不需要认证.
                .antMatchers("/login.html").permitAll()
                // .antMatchers("/hello").hasRole("ADMIN")
                // 所有请求都要经过access验证,才能访问
                .anyRequest().access("@permissionVaidator.hasPermission(request,authentication)");
    }
    @Bean
    public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
        UserDetailsService userDetailsService = new DefaultUserDetailsService(passwordEncoder);
        return userDetailsService;
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
(4). DefaultUserDetailsService
package help.lixin.security.example.userdetails;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
// 加载用户信息.
public class DefaultUserDetailsService implements UserDetailsService {
    private PasswordEncoder passwordEncoder;
    public DefaultUserDetailsService(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // TOOD lixin 去Repository中Query,如果,查找不到,则抛出异常:UsernameNotFoundException
        UserDetails user = User.withUsername("lixin")
                .password(passwordEncoder.encode("123456"))
                // 用户具有哪些资源(URI)的权限
                .authorities("/hello", "/test")
                .build();
        return user;
    }
}
(5). PermissionVaidator
package help.lixin.security.example.access;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
/**
 * 自定义权限验证
 */
@Component
public class PermissionVaidator {
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        // 请求的URL
        String requestURI = request.getRequestURI();
        // 用户登录后的权限
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        for (GrantedAuthority grantedAuthority : authorities) {
            // 建议这里用Ant表达式对URL进行判断,准确性会更好一些.
            if (grantedAuthority.getAuthority().equals(requestURI)) {
                return true;
            }
        }
        return false;
    }
}
(6). HelloController
package help.lixin.security.example.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}
(7). Application
package help.lixin.security.example;
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);
    }
}
(8). login.html
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>user login</title>
</head>
<body>
    <form action="/login" method="post">
        用户名:<input type="text" name="username">    <br/>
        密码:<input type="password" name="password">  <br/>
        <input type="submit" value="登录">
    </form>
</body>
</html>
(9). pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>help.lixin.security.example</groupId>
    <artifactId>spring-security-example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.9.RELEASE</version>
        <relativePath />
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
	
</project>
(10). 总结
通过Spring Security的简单配置,就可以实现对URL资源的认证和鉴权操作.
