引言

Spring家族庞大,每一块都像教科书般典范,这篇文章旨在学习和了解spring security,内容逐渐补充。

1 spring security概念

spring security有一块比较大的内容,23大章的内容可不是盖的。 最新5.1.1的官方文档在这里 ,各种版本可以看这里

2 spring security应用

初步应用看起来比较简单,在springboot下,只要引入一个maven依赖:

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

然后准备一个config类:

package com.seaever.qingdu.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;

import javax.sql.DataSource;

//https://www.cnblogs.com/softidea/p/5991897.html
//https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-security.html
//https://docs.spring.io/spring-security/site/docs/5.1.1.RELEASE/reference/htmlsingle/#jc-method
@Configuration
@EnableGlobalMethodSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired AccessDeniedHandler accessDeniedHandler;

    @Autowired private DataSource dataSource;

    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        //加密"0"
        String encode = bCryptPasswordEncoder.encode("admin");
        System.out.println(encode);
        //结果:$2a$10$/eEV4X7hXPzYGzOLXfCizu6h7iRisp7I116wPA3P9uRcHAKJyY4TK
    }

//https://stackoverflow.com/questions/24174884/spring-security-jdbcauthentication-default-scheme-error-on-postgresql
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .jdbcAuthentication()
                .dataSource(dataSource)
                //https://www.jianshu.com/p/9e7792d767b2
                .passwordEncoder(new BCryptPasswordEncoder())
                //.withDefaultSchema()
                .usersByUsernameQuery(
                        "select username,password, enabled from users where username=?")
                .authoritiesByUsernameQuery(
                        "select username, role from user_roles where username=?");

                //.withUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER"));
    }

//    @Override
//    public void configure(WebSecurity web) throws Exception {
//        getHttp()
//                .csrf().disable()
//                .exceptionHandling()
//                //.authenticationEntryPoint(unauthorizedHandler)
//                .accessDeniedHandler(accessDeniedHandler)
//                .and()
//                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//                .and()
//                .authorizeRequests()
//                .antMatchers("/actuator/**").permitAll()
//                .antMatchers("/actuator/**").hasAuthority("ADMIN")
//                .antMatchers(
//                        HttpMethod.GET,
//                        "/v2/api-docs"
//                        ,"/swagger-resources/**"
//                        ,"/swagger-ui.html**"
//                        //,"/webjars/**"
//                        //, "favicon.ico"
//                ).permitAll()
//                .antMatchers("/auth/**").permitAll()
//               //.anyRequest().authenticated()
//        ;
//
////        http
////                .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
////                .headers()
////                .cacheControl();
//    }
}

这里用的是mysql数据库来存储用户信息,需要用到两个表:

CREATE TABLE `users` (
  `username` varchar(20) NOT NULL,
  `password` varchar(60) NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `user_roles` (
  `username` varchar(20) NOT NULL,
  `role` varchar(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

数据表中的password内容是一个通过BCryptPasswordEncoder运算的加密串。user_roles没有主键,username一对多也没问题,如果这个表里没记录, 权限马上会失效,比如刷新页面:http://localhost:8080/swagger-ui.html,莫不是每次都会查数据库?

现在权限验证通过了,如果配置哪些需要验证,一直没生效,待了解。下列跳过的配置有效:

@Override
public void configure(WebSecurity web)  {
    web.ignoring()
            .antMatchers(                    
                    "/swagger-resources/**"
                    ,"/swagger-ui.html**"                   
            );
}

官方的测试示例