SpringSecurity前後端分離によるログイン認証の管理

18632 ワード

このケースはspringboot 2.0.4に基づいており、ログイン検証の管理のみを行い、権限の管理には関与しません.新しいことを勉強するのは急に多すぎて、めちゃくちゃになりやすいからです.       まずmaven依存を追加し、springbootが持参したspring securityを直接開くだけです.
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-securityartifactId>
dependency>

       次にconfigを構成するには、WebSecurityConfigurerAdapterを継承する必要があります.
@SpringBootConfiguration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Autowired
    private MyAuthenticationFailHandler myAuthenticationFailHandler;

    @Bean
    UserDetailsService customUserService() {
        return new MyCustomUserService();
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //      UserDetailsService
        auth.userDetailsService(customUserService()).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin().loginProcessingUrl("/user/login")
                //                  
                .successHandler(myAuthenticationSuccessHandler).failureHandler(myAuthenticationFailHandler)
                //   csrf    (      ),              。
                .and().csrf().disable();
    }
}

       認証データがデータベースから取得されている場合は、UserDetailsServiceインタフェースを実装したクラスを追加する必要があります.操作データはmybatisを使用しており、コードは羅列されません.
@Component
public class MyCustomUserService implements UserDetailsService {

    @Autowired
    private SysUserMapper sysUserMapper;

    /** *      ,  username            *    UserDetails  spring     SecurityContextHolder ,        */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        MyUserDetails myUserDetails = new MyUserDetails();
        myUserDetails.setUsername(username);
        SysUser sysUser = sysUserMapper.selectByKeyword(username);
        myUserDetails.setPassword(sysUser.getPassword());
        return myUserDetails;
    }
}

       上のコードのMyUserDetailsは、UserDetailsインタフェースを実装し、戻りオブジェクトをカスタマイズしています.MyUserDetailsを使用しなくてもよい場合は、デフォルトのUserクラスを使用できますが、検証だけでは複雑です.不要な検証プロパティを簡略化するために、UserDetailsの下にあるUserのコードのプロパティをカスタマイズします.(雑然としているのか初心者には)
    private static final long serialVersionUID = 500L;
    private static final Log logger = LogFactory.getLog(User.class);
    private String password;
    private final String username;
    private final Set authorities;
    private final boolean accountNonExpired;
    private final boolean accountNonLocked;
    private final boolean credentialsNonExpired;
    private final boolean enabled;

       これはカスタマイズされたMyUserDetailsクラスで、不要な属性がビジネスに与える影響を排除しています.(属性は3つしか残っていません)
@Component
public class MyUserDetails implements UserDetails {

    private String username;

    private String password;

    private Collection extends GrantedAuthority> authorities;

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setAuthorities(Collection extends GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

    @Override
    public Collection extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

       あと2つ登録してクラスに行きますが、この2つのクラスは勝手に書いて、業務のニーズに応じて書けばいいです.実はspring security自体もデフォルトのログイン失敗とログイン成功の行方を実現しているが、前後の分離の下で、バックエンドはページのジャンプやエラーメッセージなどを担当していない.バックエンドでは、登録情報付きJson形式のデータもフロントエンドに返されるので、これらの要件を満たすには、AuthenticationFailureHandlerおよびAuthenticationSuccessHandlerインタフェースを実装する必要があります.MyAuthenticationSuccessHandlerクラスのonAuthenticationFailureメソッドは、例外(エラー)情報を印刷できることに注意してください.
@Component
public class MyAuthenticationFailHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        //     
        httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
        //         token(  head  )
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
        httpServletResponse.getWriter().write(200);
    }
}

@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        //     
        httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
        //         token(  head  )
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
        httpServletResponse.getWriter().write(e.getMessage());
    }
}

       次に、WebSecurityConfigurationクラスのloginProcessingUrl("/user/login")の値と一致するフロントエンドのログインコードです.もちろん、以下のコードはajaxで置き換えることもできます.fromフォームでログインする必要はありません.
<form action='/user/login' method='POST'>
    <table>
        <tr>
            <td>User:td>
            <td><input type='text' name='username' value=''>td>
        tr>
        <tr>
            <td>Password:td>
            <td><input type='password' name='password'/>td>
        tr>
    table>
form>

       以上,単純なspring securityの前後端分離での運用例である.しかし、このように書くだけでは、分からない人が見ても霧の水で、spring securityの強さを十分に示すことはできません.
--------------------------------------
WebSecurityConfigurationクラスWebSecurityConfigurationクラスでは、カスタムのMyAuthenticationSuccessHandlerとMyAuthenticationFailHandlerをクラスに注入し、loginProcessingUrl("/user/login")の後にこの2つのクラスの使用をアクティブにする必要があります.
@Autowired
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Autowired
private MyAuthenticationFailHandler myAuthenticationFailHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.formLogin().loginProcessingUrl("/user/login")
            //                  
            .successHandler(myAuthenticationSuccessHandler).failureHandler(myAuthenticationFailHandler)
            //   csrf    (      ),              。
            .and().csrf().disable();
}

カスタムMyUserDetailsServiceクラスもWebSecurityConfigurationクラスで注入およびアクティブ化する必要があります
@Bean
UserDetailsService customUserService() {
    return new MyCustomUserService();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //      UserDetailsService
    auth.userDetailsService(customUserService()).passwordEncoder(new BCryptPasswordEncoder());
}

       上のコードには.passwordEncoder(new BCryptPasswordEncoder()という意味でパスワード暗号化の方法を指定します.ここではBCrypt暗号化方式を採用している.言い換えれば、spring securityがフロントエンドから渡されたパスワードを取得すると、自動的にBCryptでパスワードを暗号化し、データベースのパスワードと照合します.データベースに保存されているパスワードもBCryptで暗号化されたパスワードでなければなりません.       そう言えば、カスタム暗号化方式も指定できるのではないでしょうか.はい、実現も簡単です.PasswordEncoderインタフェースを実現すればいいです..passwordEncoder(new BCryptPasswordEncoder()を.passwordEncoder(new MyPasswordEncoder()に変更すればよい.
@Component
public class MyPasswordEncoder implements PasswordEncoder {

    @Override
    public String encode(CharSequence charSequence) {
        return SecurityUtil.encrypt(charSequence.toString());
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return encode(charSequence).equals(s);
    }
}

次にこれについてお話しします
http.formLogin().loginProcessingUrl("/user/login")
          //                  
          .successHandler(myAuthenticationSuccessHandler).failureHandler(myAuthenticationFailHandler)
          //   csrf    (      ),              。
          .and().csrf().disable();

       これについて一般的に書くとhttp.forLogin().loginPage("/login")などがありますが、これはカスタムログインページで、デフォルトは/loginです.つまり、spring security保護のリクエストにアクセスしたときにログインしていないことに気づいたら、指定したページにジャンプし、デフォルトを使用するか書かないとspring securityがデフォルトのログインページを書いてくれたことにジャンプします.前後端で分離すると、これは放っておきます.loginProcessingUrl("/user/login")はログイン要求です.
上のものを見るだけでは少し飲み込んでいるようで、別の博文を見て、主に登録検証の過程といくつかのソースコードの浅い分析を分析することをお勧めします.SpringSecurityログイン検証手順とソースコードの浅い分析