1. 程式人生 > >SpringBoot2.0高階案例(12):整合 SpringSecurity 框架,實現使用者許可權安全管理

SpringBoot2.0高階案例(12):整合 SpringSecurity 框架,實現使用者許可權安全管理

一、Security簡介

1、基礎概念

Spring Security是一個能夠為基於Spring的企業應用系統提供宣告式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring的IOC,DI,AOP(面向切面程式設計)功能,為應用系統提供宣告式的安全訪問控制功能,減少了為安全控制編寫大量重複程式碼的工作。

2、核心API解讀

1)、SecurityContextHolder

最基本的物件,儲存著當前會話使用者認證,許可權,鑑權等核心資料。SecurityContextHolder預設使用ThreadLocal策略來儲存認證資訊,與執行緒繫結的策略。使用者退出時,自動清除當前執行緒的認證資訊。

初始化原始碼:明顯使用ThreadLocal執行緒。

private static void initialize() {
    if (!StringUtils.hasText(strategyName)) {
        strategyName = "MODE_THREADLOCAL";
    }
    if (strategyName.equals("MODE_THREADLOCAL")) {
        strategy = new ThreadLocalSecurityContextHolderStrategy();
    } else if (strategyName.equals("MODE_INHERITABLETHREADLOCAL")) {
        strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
    } else if (strategyName.equals("MODE_GLOBAL")) {
        strategy = new GlobalSecurityContextHolderStrategy();
    } else {
        try {
            Class<?> clazz = Class.forName(strategyName);
            Constructor<?> customStrategy = clazz.getConstructor();
            strategy = (SecurityContextHolderStrategy)customStrategy.newInstance();
        } catch (Exception var2) {
            ReflectionUtils.handleReflectionException(var2);
        }
    }
    ++initializeCount;
}

2)、Authentication

原始碼

public interface Authentication extends Principal, Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();
    Object getCredentials();
    Object getDetails();
    Object getPrincipal();
    boolean isAuthenticated();
    void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

原始碼分析

1)、getAuthorities,許可權列表,通常是代表權限的字串集合;
2)、getCredentials,密碼,認證之後會移出,來保證安全性;
3)、getDetails,請求的細節引數;
4)、getPrincipal, 核心身份資訊,一般返回UserDetails的實現類。

3)、UserDetails

封裝了使用者的詳細的資訊。

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();
    String getPassword();
    String getUsername();
    boolean isAccountNonExpired();
    boolean isAccountNonLocked();
    boolean isCredentialsNonExpired();
    boolean isEnabled();
}

4)、UserDetailsService

實現該介面,自定義使用者認證流程,通常讀取資料庫,對比使用者的登入資訊,完成認證,授權。

public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

5)、AuthenticationManager

認證流程頂級介面。可以通過實現AuthenticationManager介面來自定義自己的認證方式,Spring提供了一個預設的實現,ProviderManager。

public interface AuthenticationManager {
    Authentication authenticate(Authentication var1) throws AuthenticationException;
}

二、與SpringBoot2整合

1、流程描述

1)、三個頁面分類,page1、page2、page3
2)、未登入授權都不可以訪問
3)、登入後根據使用者許可權,訪問指定頁面
4)、對於未授權頁面,訪問返回403:資源不可用

2、核心依賴

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

3、核心配置

/**
 * EnableWebSecurity註解使得SpringMVC集成了Spring Security的web安全支援
 */
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 許可權配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置攔截規則
        http.authorizeRequests().antMatchers("/").permitAll()
                 .antMatchers("/page1/**").hasRole("LEVEL1")
                 .antMatchers("/page2/**").hasRole("LEVEL2")
                 .antMatchers("/page3/**").hasRole("LEVEL3");
        // 配置登入功能
        http.formLogin().usernameParameter("user")
                .passwordParameter("pwd")
                .loginPage("/userLogin");
        // 登出成功跳轉首頁
        http.logout().logoutSuccessUrl("/");
        //開啟記住我功能
        http.rememberMe().rememberMeParameter("remeber");
    }
    /**
     * 自定義認證資料來源
     */
    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception{
        builder.userDetailsService(userDetailService())
                .passwordEncoder(passwordEncoder());
    }
    @Bean
    public UserDetailServiceImpl userDetailService (){
        return new UserDetailServiceImpl () ;
    }
    /**
     * 密碼加密
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    /*
     * 硬編碼幾個使用者
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("spring").password("123456").roles("LEVEL1","LEVEL2")
                .and()
                .withUser("summer").password("123456").roles("LEVEL2","LEVEL3")
                .and()
                .withUser("autumn").password("123456").roles("LEVEL1","LEVEL3");
    }
    */
}

4、認證流程

@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Resource
    private UserRoleMapper userRoleMapper ;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 這裡可以捕獲異常,使用異常對映,丟擲指定的提示資訊
        // 使用者校驗的操作
        // 假設密碼是資料庫查詢的 123
        String password = "$2a$10$XcigeMfToGQ2bqRToFtUi.sG1V.HhrJV6RBjji1yncXReSNNIPl1K";
        // 假設角色是資料庫查詢的
        List<String> roleList = userRoleMapper.selectByUserName(username) ;
        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>() ;
        /*
         * Spring Boot 2.0 版本踩坑
         * 必須要 ROLE_ 字首, 因為 hasRole("LEVEL1")判斷時會自動加上ROLE_字首變成 ROLE_LEVEL1 ,
         * 如果不加字首一般就會出現403錯誤
         * 在給使用者賦許可權時,資料庫儲存必須是完整的許可權標識ROLE_LEVEL1
         */
        if (roleList != null && roleList.size()>0){
            for (String role : roleList){
                grantedAuthorityList.add(new SimpleGrantedAuthority(role)) ;
            }
        }
        return new User(username,password,grantedAuthorityList);
    }
}

5、測試介面

@Controller
public class PageController {
    /**
     * 首頁
     */
    @RequestMapping("/")
    public String index (){
        return "home" ;
    }
    /**
     * 登入頁
     */
    @RequestMapping("/userLogin")
    public String loginPage (){
        return "pages/login" ;
    }
    /**
     * page1 下頁面
     */
    @PreAuthorize("hasAuthority('LEVEL1')")
    @RequestMapping("/page1/{pageName}")
    public String onePage (@PathVariable("pageName") String pageName){
        return "pages/page1/"+pageName ;
    }
    /**
     * page2 下頁面
     */
    @PreAuthorize("hasAuthority('LEVEL2')")
    @RequestMapping("/page2/{pageName}")
    public String twoPage (@PathVariable("pageName") String pageName){
        return "pages/page2/"+pageName ;
    }
    /**
     * page3 下頁面
     */
    @PreAuthorize("hasAuthority('LEVEL3')")
    @RequestMapping("/page3/{pageName}")
    public String threePage (@PathVariable("pageName") String pageName){
        return "pages/page3/"+pageName ;
    }
}

6、登入介面

這裡要和Security的配置檔案相對應。

<div align="center">
    <form th:action="@{/userLogin}" method="post">
        使用者名稱:<input name="user"/><br>
        密&nbsp;&nbsp;&nbsp;碼:<input name="pwd"><br/>
        <input type="checkbox" name="remeber"> 記住我<br/>
        <input type="submit" value="Login">
    </form>
</div>

三、原始碼地址

GitHub地址:知了一笑
https://github.com/cicadasmile/middle-ware-parent
碼雲地址:知了一笑
https://gitee.com/cicadasmile/middle-ware-parent

相關推薦

SpringBoot2.0高階案例(12)整合 SpringSecurity 框架實現使用者許可權安全管理

一、Security簡介 1、基礎概念 Spring Security是一個能夠為基於Spring的企業應用系統提供宣告式的安全訪

SpringBoot2.0高階案例(10)整合 JWT 框架解決Token跨域驗證問題

GitHub原始碼地址:知了一笑 https://github.com/cicadasmile/middle-ware-paren

SpringBoot2.0高階案例(09)整合 ElasticSearch框架,實現高效能搜尋引擎

本文原始碼 碼雲地址:知了一笑 https://gitee.com/cicadasmile/middle-ware-parent

SpringBoot2.0高階案例(08)整合 Dubbo框架 ,實現RPC服務遠端呼叫

一、Dubbo框架簡介 1、框架依賴 圖例說明: 1)圖中小方塊 Protocol, Cluster, Proxy, Servi

SpringBoot2.0高階案例(02) 整合 RocketMQ ,實現請求非同步處理

本文原始碼 碼雲地址:知了一笑 https://gitee.com/cicadasmile/middle-ware-parent

SpringBoot2.0高階案例(03)整合 JavaMail ,實現非同步傳送郵件

本文原始碼 碼雲地址:知了一笑 https://gitee.com/cicadasmile/middle-ware-parent

SpringBoot2.0高階案例(05)整合 Swagger2 ,構建介面管理介面

一、Swagger2簡介 1、Swagger2優點 整合到Spring Boot中,構建強大RESTful API文件。省去介面文

SpringBoot2.0高階案例(06)整合 QuartJob ,實現定時器實時管理

一、QuartJob簡介 1、一句話描述 Quartz是一個完全由java編寫的開源作業排程框架,形式簡易,功能強大。 2、核心A

SpringBoot2.0高階案例(07) 整合Redis叢集 ,實現訊息佇列場景

本文原始碼 GitHub地址:知了一笑 https://github.com/cicadasmile/middle-ware-pa

SpringBoot2高階案例(11)整合 FastDFS 中介軟體實現檔案分散式管理

一、FastDFS簡介 1、FastDFS作用 FastDFS是一個開源的輕量級分散式檔案系統,它對檔案進行管理,功能包括:檔案儲

SpringBoot--01.SpringBoot2.0入門案例

一、SpringBoot簡介 1、SpringBoot概述(簡化配置、開箱即用) - 為所有 Spring 的開發者提供一個非常快速的、廣泛接受的入門體驗 - 開箱即用(啟動器starter-其實就是SpringBoot提供的一個jar包),但通過自己設定參 (.properties),

微服務 SpringBoot 2.0(九)整合Mybatis

我是SQL小白,我選Mybatis —— Java面試必修 引言 在第五章我們已經整合了Thymeleaf頁面框架,第七章也整合了JdbcTemplate,那今天我們再結合資料庫整合Mybatis框架 在接下來的文章中,我會用一個開源的部落格原始碼來做講解

Springboot2.0啟動報錯java.lang.NoClassDefFoundError: ch/qos/logback/core/spi/LifeCycle

springboot2.0啟動報錯: java.lang.NoClassDefFoundError: ch/qos/logback/core/spi/LifeCycle     at java.lang.ClassLoader.defineClass1(Native Met

springBoot2.0 MyBatis Redis 及RedisCache 整合附demo

springboot2.0 + mybatis 或者 springboot2.0 + redis 在網上可以找到很多資料,但是大都不全或者有這樣那樣的問題,所以便自己動手寫了個demo,能只用 yaml 配置的,儘量不再寫程式碼。 pom.xml <?xml ver

案例12地下人防電影院防火案例分-析案例13地下汽車庫建築

內容 技術 分享 bubuko image 電影院 ima mage 技術分享 情景描述    分5個防火分區 安全疏散    簡答題 地下汽車庫的情景分析 分析內容 建築分類和耐火等級 防火分區 有人員

springboot學習入門簡易版四---springboot2.0靜態資源訪問及整合freemarker視圖層

nbsp 規則 pri stat path 整合 位置 啟動程序 -- 2.4.4 SpringBoot靜態資源訪問(9) Springboot默認提供靜態資源目錄位置需放在classpath下,目錄名需要符合如下規則 /static /public /resour

汽車行業案例分享海馬汽車選擇藍雲EasyTrack專案管理軟體

專案背景 上海海馬汽車研發有限公司是海馬汽車在上海的研發中心。 上海海馬汽車研發有限公司是海馬鄭州的全資子公司,是整車研發機構,上海海馬擁有造型、設計、試製、試驗裝置,致力於新產品的設計、產品的改進設計、樣車的試製試驗等業務,並與多家專業服務機構開展了緊密合作,形成了完整的合作團隊。 汽車研發有著技術複

整合第三方框架報錯NoSuchFieldErrorlogger

logger專案中使用springboot的版本是2.0.1.RELEASE,該版本依賴的spring版本為5.0.5.RELEASE(logger在spring版本5.0.7.RELEASE中),在專案中新增對應的spring-beans版本,問題解決了。 <dep

機器學習教程 之 Boosting 與 bagging整合學習框架

整合學習是機器學習演算法中非常耀眼的一類方法,它通過訓練多個基本的分類器(如支援向量機、神經網路、決策樹等),再通過基本分類器的決策融合,構成一個完整的具有更強學習分辨能力的學習器。在整合學習中,那些基本學習器一般被稱為為“弱學習器“,機器學習的目的就是通過整合

MyEclipse整合SSM框架(四)整合前端頁面通過ajax請求獲得資料

Spring+SpringMVC+Mybatis 框架已經搭建完成,其中包括:(1)maven工程的搭建 (2)框架所需要的配置檔案的配置 (3)Mybatis 建立逆向工程連結資料庫。相應的配置檔案參見前幾篇部落格。此篇整理前端頁面傳送ajax 請求到後端,後端通過 Myb