SpringSecurity入門1---基於內存的登錄

代碼地址

開啓SpringBoot項目登錄校驗

在SpringBoot項目中引入SpringSecurity的依賴之後,項目就會默認開始基於HttpBasic的校驗,用戶默認爲user,密碼在項目啓動的時候會在控制檯中進行打印,隨便寫一個controller啓動並對其進行訪問,會被攔截並彈出登錄窗口

    <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>

在這裏插入圖片描述

默認表單登錄

在實際項目中很少使用Http的登錄,接下來介紹一下如何開啓SpringSecurity提供的默認表單登錄

創建一個WebSecurityConfig繼承WebSecurityConfigurerAdapter,重寫入參爲HttpSecurity httpconfigure方法

/**
 * @Auther: Anntly
 * @Date: 2020/4/2 09:20
 * @Description:
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 讓所有請求都需要權限驗證
                .anyRequest().authenticated()
                .and()
                // 開啓表單登錄
                .formLogin();
    }
}

注意要開啓@EnableWebSecurity註解,該註解組合了@Configuration會將其作爲配置文件注入Spring容器中,
在這裏插入圖片描述

使用自定義登錄界面

默認提供的登錄界面有些簡陋,一般都會開發我們自己的登錄界面,我是直接去模板網站找的登錄界面,其中核心的頁面代碼如下,前端代碼以及資源放在resource/sstatic

						<form action="/login" method="POST">
                            <div class="form-group">
                                <label for="username">User-Name</label>
                                <input id="username" class="form-control" name="username" value="" required autofocus>
                            </div>
                            <div class="form-group">
                                <label for="password">Password
                                    <a href="forgot.html" class="float-right">
                                        Forgot Password?
                                    </a>
                                </label>
                                <input id="password" type="password" class="form-control" name="password" required
                                       data-eye>
                            </div>
                            <div class="form-group">
                                <label>
                                    <input type="checkbox" name="remember"> Remember Me
                                </label>
                            </div>
                            <div class="form-group no-margin">
                                <button type="submit" class="btn btn-primary btn-block">
                                    Login
                                </button>
                            </div>
                            <div class="margin-top20 text-center">
                                Don't have an account? <a href="register.html">Create One</a>
                            </div>
                        </form>

代碼地址中可以查看詳細代碼,其中form的action的訪問地址定義爲/login,這個需要在配置文件進行配置

修改上一步的WebSecurityConfig文件

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 對靜態資源放行
                .antMatchers("/css/**", "/img/**", "/js/**", "/bootstrap/**").permitAll()
                .anyRequest().authenticated()
                .and()
                // 指定登錄界面
                .formLogin().loginPage("/myLogin.html")
                // 指定處理登錄的請求url
                .loginProcessingUrl("/login")
                // 對登錄相關頁面請求放行
                .permitAll()
                // 使登錄頁不受限
                .and()
                // 關閉csrf
                .csrf().disable();
    }

antMatchers使用了ANT模式,其中?表示匹配任意單個字符,*表示匹配0或者任意數量的字符,**表示匹配0或更多的目錄

重啓項目後,再次訪問請求就能夠進入到自定義的登錄界面
在這裏插入圖片描述

使用內存用戶

每次用戶密碼打印到控制檯是不合理的,呼應本章的標題,接下來在內存中配置我們的用戶;在之前我們重寫的configure方法入參爲HttpSecurity,接下來再重寫一個入參爲AuthenticationManagerBuilder

/**
 * @Auther: Anntly
 * @Date: 2020/4/2 09:20
 * @Description:
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 開啓註解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 對靜態資源放行
                .antMatchers("/css/**", "/img/**", "/js/**", "/bootstrap/**").permitAll()
                .anyRequest().authenticated()
                .and()
                // 指定登錄界面
                .formLogin().loginPage("/myLogin.html")
                // 指定處理登錄的請求url
                .loginProcessingUrl("/login")
                // 對登錄相關頁面請求放行
                .permitAll()
                // 使登錄頁不受限
                .and()
                // 關閉csrf
                .csrf().disable();
    }

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    	// 配置兩個用戶,user和admin,密碼均爲123,分別持有角色USER和ADMIN
        auth.inMemoryAuthentication()
                .passwordEncoder(passwordEncoder())
                .withUser("user")
                .password(passwordEncoder().
                        encode("123")).roles("USER")
                .and()
                .withUser("admin")
                .password(passwordEncoder().
                        encode("123")).roles("ADMIN");
    }
}

在代碼中可以看到引入了BCryptPasswordEncoder這個類,這個類主要用於對密碼的加密,在SpringSecurity5之後必須對密碼進行加密後才能使用,Spring默認並未選用MD5加密的方式,而是選用了這種,因爲這種方式加密選用的隨機salt進行加密,相同的字符串加密出來的結果也不一樣,也就避免了MD5撞庫的危險

除了用戶密碼之外還配置了角色,在配置類上還添加了@EnableGlobalMethodSecurity(prePostEnabled = true)用戶開啓方法權限校驗,即訪問對應的controller需要對應的角色,在controller中使用如下

	@GetMapping("/admin")
    @PreAuthorize("hasAnyRole('ADMIN')")
    public String api(){
        return "hello admin";
    }
    @GetMapping("/user")
    @PreAuthorize("hasAnyRole('USER')")
    public String api(){
        return "hello user";
    }

接下里重啓項目,登錄user用戶
在這裏插入圖片描述
訪問user路徑,可以看到hello user
在這裏插入圖片描述
再訪問admin,會發現無法訪問,異常爲403即未授權,401爲登錄驗證失敗
在這裏插入圖片描述
再登錄admin後訪問admih,可以看到能夠看到hello admin
在這裏插入圖片描述
至此基於內存的登錄方式講解的差不多了,除此之外,現在基本上是前後端分離的方式,後端校驗後一般是返回前端json字符串,這個可以用成功/失敗處理器(successHandler/failureHandler)來實現,可以使用類實現了再注入,下面爲了方便演示直接就內部類實現了

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/css/**", "/img/**", "/js/**", "/bootstrap/**").permitAll()
                .antMatchers("/app/api/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().loginPage("/myLogin.html")
                .loginProcessingUrl("/login")
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write("{\"error_code\":\"0\",\"message\":\"歡迎登陸系統\"}");
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write("{\"error_code\":\"401\",\"name\"" + e.getClass() +
                                "\",\"message\":\":\"" + e.getMessage() + "\"}");
                    }
                })
                .permitAll()
                // 使登錄頁不受限
                .and()
                .csrf().disable();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章