SpringSecurityプローブ

10454 ワード

stater

// 

            org.springframework.boot
            spring-boot-starter-security

コントロールクラステストを書く
@RestController
@RequestMapping("/test")
public class TestController {
    @GetMapping("hello")
    public String hello(){
        return "hello";
    }
}

実行に成功するとパスワードが表示されます
  user
Using generated security password: 9afa3ef4-035c-44bc-8dd2-c9e0e8121638

ろ過チェーン


SpringSecurity本質はフィルタチェーンである
サービスリクエスト時に作成するには、各フィルタを次のステップに進むにはローにします.

FilterSecurityInterceptorメソッドレベルの権限フィルタ、基本述部フィルタチェーンの下部

doFilter  
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        this.invoke(new FilterInvocation(request, response, chain));
    }


invoke  
    
InterceptorStatusToken token = super.beforeInvocation(filterInvocation);
// 

ExceptionTranslationFilter例外フィルタは、認証承認プロセス中に放出された例外を処理するために使用されます。

doFilter   

U s e r m e P a s s s w o r d AuthenticationFilterは/loginのPOST要求をブロックし、フォームのユーザー名、パスワードを検証します。

 private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/login", "POST");

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        } else {
            String username = this.obtainUsername(request);
            username = username != null ? username : "";
            username = username.trim();
            String password = this.obtainPassword(request);
            password = password != null ? password : "";
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
            this.setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }

フィルタロードプロセス


Springbootはspringsecurityを自動化した構成スキームを行うので、依存を導入すれば追加の構成を必要としません.
1、SpringSecurityを使用してフィルターを配置するDelegatingFilterProxy
doFilter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    Filter delegateToUse = this.delegate;
    if (delegateToUse == null) {
        synchronized(this.delegateMonitor) {
            delegateToUse = this.delegate;
            if (delegateToUse == null) {
                WebApplicationContext wac = this.findWebApplicationContext();
                if (wac == null) {
                    throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");
                }

                delegateToUse = this.initDelegate(wac);
            }

            this.delegate = delegateToUse;
        }
    }

    this.invokeDelegate(delegateToUse, request, response, filterChain);
}


initDelegate
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
        String targetBeanName = this.getTargetBeanName();
        Assert.state(targetBeanName != null, "No target bean name set");
        Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class);
        if (this.isTargetFilterLifecycle()) {
            delegate.init(this.getFilterConfig());
        }

        return delegate;
    }

doFilterでは初期化メソッドinitDelegateが呼び出され、フィルタの名前targetBeanNameがFilterChainProxyという内蔵フィルタが得られます
// 
List filters = this.getFilters((HttpServletRequest)firewallRequest);

private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest)request);
        HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse)response);
        List filters = this.getFilters((HttpServletRequest)firewallRequest);
        if (filters != null && filters.size() != 0) {
            if (logger.isDebugEnabled()) {
                logger.debug(LogMessage.of(() -> {
                    return "Securing " + requestLine(firewallRequest);
                }));
            }

            FilterChainProxy.VirtualFilterChain virtualFilterChain = new FilterChainProxy.VirtualFilterChain(firewallRequest, chain, filters);
            virtualFilterChain.doFilter(firewallRequest, firewallResponse);
        } else {
            if (logger.isTraceEnabled()) {
                logger.trace(LogMessage.of(() -> {
                    return "No security for " + requestLine(firewallRequest);
                }));
            }

            firewallRequest.reset();
            chain.doFilter(firewallRequest, firewallResponse);
        }
    }
    
    
private List getFilters(HttpServletRequest request) {
        int count = 0;
        Iterator var3 = this.filterChains.iterator();

        SecurityFilterChain chain;
        do {
            if (!var3.hasNext()) {
                return null;
            }

            chain = (SecurityFilterChain)var3.next();
            if (logger.isTraceEnabled()) {
                ++count;
                logger.trace(LogMessage.format("Trying to match request against %s (%d/%d)", chain, count, this.filterChains.size()));
            }
        } while(!chain.matches(request));

        return chain.getFilters();
    }

FilterChainProxyでは、そのフィルタをフィルタチェーンにロードします.

2つの重要なインタフェース


ユーザー名の固定userは、パスワードが自動的に生成されますが、変更するに違いありません.
1.クラス継承U s e r n a m e P a s s s s w o r d AuthenticationFilterを作成し、その3つのメソッド、a t t e m p t Authentication、successfulAuthentication、unsuccessfulAuthentication、
2.クラス実装UserDetailsServiceインタフェースを作成し、クエリー・データベースのプロセスを記述し、セキュリティ・フレームワークのオブジェクトであり、自分で書いたものではないUserオブジェクトを返します.

UserDetailsService


このインタフェースはデータベースに行って物を調べる過程です.

PasswordEcoder


データ暗号化インタフェース、返されるUserオブジェクト内のパスワードの暗号化

ログインのユーザー名とパスワードの設定


第一に、プロファイルによる構成
spring:
  security:
    user:
      name: "shuaikb"
      password: "shuaikb"

2つ目は、クラスを構成することによって
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String password = bCryptPasswordEncoder.encode("123");
        auth.inMemoryAuthentication().withUser("test").password(password).roles("admin");

    }
}
// super.configure(auth);

第三に、カスタム作成実装クラス
プロファイルとコンフィギュレーションクラスにユーザーとパスワードが設定されていない場合は、UserDetailsServiceというインタフェースを探します.
1.クラス継承U s e r n a m e P a s s s s w o r d AuthenticationFilterを作成し、その3つのメソッド、a t t e m p t Authentication、successfulAuthentication、unsuccessfulAuthentication、
2.クラス実装UserDetailsServiceインタフェースを作成し、クエリー・データベースのプロセスを記述し、セキュリティ・フレームワークのオブジェクトであり、自分で書いたものではないUserオブジェクトを返します.
@Configuration
public class SecurityConfig3 extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;


    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
}
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // 
        List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User("shuaikb",new BCryptPasswordEncoder().encode("123"),auths);
    }
}

データベースの統合


            mysql
            mysql-connector-java



            com.baomidou
            mybatis-plus-boot-starter
            3.4.3.1

エンティティークラス
/**
 * @Author Shuaikb
 * @create 2021/8/23 20:54
 */
@Data
public class Users {
    private String id;
    private String usernma;
    private String password;
}

mapperインタフェース
/**
 * @Author Shuaikb
 * @create 2021/8/23 20:56
 */
public interface UserMapper extends BaseMapper{
}

サービスにインタフェースを注入する
@Autowired
    private UserMapper userMapper;

具体判断コード
/**
 * @Author Shuaikb
 * @create 2021/8/22 23:43
 */
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("username",username);
        Users users = userMapper.selectOne(queryWrapper);
        if (users ==null){
            throw new UsernameNotFoundException(" !");
        }
        // 
        List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User(users.getUsernma(),new BCryptPasswordEncoder().encode(users.getPassword()),auths);
    }
}

 mapper  
@MapperScan("com.example.springsecurity.mapper")