1.在pom.xml加入SpringSecurity的依賴
<!-- SpringSecurity對(duì)Web應(yīng)用進(jìn)行權(quán)限管理 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<!-- SpringSecurity配置 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<!-- SpringSecurity標(biāo)簽庫(kù) -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
2.在web.xml加入springsecurity 的過(guò)濾器配置
<!-- springsecurity 的過(guò)濾器配置 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.編寫一個(gè)配置類WebAppSecurityConfig,該類要繼承WebSecurityConfigurerAdapter
//表示當(dāng)前類是一個(gè)配置類 @Configuration //啟用web環(huán)境下權(quán)限配置功能 @EnableWebSecurity public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter{ }
4.在配置類中實(shí)現(xiàn)兩個(gè)方法protected void configure(HttpSecurity security),configure(AuthenticationManagerBuilder builder)。
@Override protected void configure(AuthenticationManagerBuilder builder) throws Exception { // 裝配userDetailsService對(duì)象 builder .userDetailsService(userDetailsService).passwordEncoder(getBCryptPasswordEncoder()); } @Override protected void configure(HttpSecurity security) throws Exception { // 準(zhǔn)備JdbcTokenRepositoryImpl對(duì)象 JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl(); tokenRepository.setDataSource(dataSource); // 創(chuàng)建數(shù)據(jù)庫(kù)表 tokenRepository.setCreateTableOnStartup(true); tokenRepository.initDao(); security .authorizeRequests() // 對(duì)請(qǐng)求進(jìn)行授權(quán) .antMatchers("/index.jsp") // 針對(duì)/index.jsp路徑進(jìn)行授權(quán) .permitAll() // 可以無(wú)條件訪問(wèn) .antMatchers("/layui/**") // 針對(duì)/layui目錄下所有資源進(jìn)行授權(quán) .permitAll() // 可以無(wú)條件訪問(wèn) .antMatchers("/level1/**") // 針對(duì)/level1/**路徑設(shè)置訪問(wèn)要求 .hasRole("學(xué)徒") // 要求用戶具備“學(xué)徒”角色才可以訪問(wèn) .antMatchers("/level2/**") // 針對(duì)/level2/**路徑設(shè)置訪問(wèn)要求 .hasAuthority("內(nèi)門弟子") // 要求用戶具備“內(nèi)門弟子”權(quán)限才可以訪問(wèn) .and() .authorizeRequests() // 對(duì)請(qǐng)求進(jìn)行授權(quán) .anyRequest() // 任意請(qǐng)求 .authenticated() // 需要登錄以后才可以訪問(wèn) .and() .formLogin() // 使用表單形式登錄 // 關(guān)于loginPage()方法的特殊說(shuō)明 // 指定登錄頁(yè)的同時(shí)會(huì)影響到:“提交登錄表單的地址”、“退出登錄地址”、“登錄失敗地址” // /index.jsp GET - the login form 去登錄頁(yè)面 // /index.jsp POST - process the credentials and if valid authenticate the user 提交登錄表單 // /index.jsp?error GET - redirect here for failed authentication attempts 登錄失敗 // /index.jsp?logout GET - redirect here after successfully logging out 退出登錄 .loginPage("/index.jsp") // 指定登錄頁(yè)面(如果沒(méi)有指定會(huì)訪問(wèn)SpringSecurity自帶的登錄頁(yè)) // loginProcessingUrl()方法指定了登錄地址,就會(huì)覆蓋loginPage()方法中設(shè)置的默認(rèn)值/index.jsp POST .loginProcessingUrl("/do/login.html") // 指定提交登錄表單的地址 .usernameParameter("loginAcct") // 定制登錄賬號(hào)的請(qǐng)求參數(shù)名 默認(rèn)為username .passwordParameter("userPswd") // 定制登錄密碼的請(qǐng)求參數(shù)名 默認(rèn)為password .defaultSuccessUrl("/main.html") // 登錄成功后前往的地址 .and() .csrf() .disable() // 禁用CSRF功能 .logout() // 開(kāi)啟退出功能 .logoutUrl("/do/logout.html") // 指定處理退出請(qǐng)求的URL地址 .logoutSuccessUrl("/index.jsp") // 退出成功后前往的地址 .and() .exceptionHandling() // 指定異常處理器 // .accessDeniedPage("/to/no/auth/page.html") // 訪問(wèn)被拒絕時(shí)前往的頁(yè)面 .accessDeniedHandler(new AccessDeniedHandler() { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { request.setAttribute("message", "抱歉!您無(wú)法訪問(wèn)這個(gè)資源!☆☆☆"); request.getRequestDispatcher("/WEB-INF/views/no_auth.jsp").forward(request, response); } }) .and() .rememberMe() // 開(kāi)啟記住我功能 .tokenRepository(tokenRepository) // 裝配token倉(cāng)庫(kù) ; }
5.在啟動(dòng)時(shí)會(huì)報(bào)一個(gè)錯(cuò)誤
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' available
原因:
三大組件啟動(dòng)順序:
首先:ContextLoaderListener初始化,創(chuàng)建Spring的IOC容器
其次:DelegatingFilterProxy初始化,查找IOC容器,查找Bean
最后:DispatcherServlet初始化,創(chuàng)建SpringMVC的IOC容器
項(xiàng)目啟動(dòng)過(guò)程中,先進(jìn)行ContextLoaderListener初始化加載spring配置文件生成springIOC容器,然后加載過(guò)濾器Filter,加載到DelegatingFilterProxy時(shí)需要在IOC容器中找一個(gè)SpringSecurityFilterChain的bean(默認(rèn)會(huì)去Spring的IOC容器中去找),最后DispatcherServlet初始化加載SpringMvc配置文件生成SpringMVC的IOC容器。為了讓SpringSecurity對(duì)瀏覽器請(qǐng)求進(jìn)行權(quán)限控制,需要讓SpringMVC來(lái)掃描WebAppSecurityConfig。所以DelegatingFilterProxy需要的bean在SpringMvc的IOC容器中。導(dǎo)致找不到這個(gè)Bean。
解決辦法:
方法一.讓SpringMVC的IOC容器和Spring的IOC容器合并,全部用DispatcherServlet來(lái)加載所有配置文件。
具體做法:
①在web.xml文件中注釋掉監(jiān)聽(tīng)器ContextLoaderListener的配置
②在springmvc配置文件中加載spring配置文件
<!-- 導(dǎo)入其他配置文件 -->
<import resource="classpath:application*.xml"/>
方法二:修改源碼
具體做法:
1.初始化時(shí)直接跳過(guò)查找IOC容器
①創(chuàng)建org.springframework.web.filter包,在這個(gè)包下創(chuàng)建類DelegatingFilterProxy,將源碼拷貝過(guò)來(lái)。
按住Ctrl點(diǎn)擊<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>,進(jìn)入源碼,拷貝出來(lái)。
<!-- springsecurity 的過(guò)濾器配置 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
②去230行注釋掉初始化查找IOC的代碼
// Fetch Spring root application context and initialize the delegate early, // if possible. If the root application context will be started after this // filter proxy, we'll have to resort to lazy initialization. // WebApplicationContext wac = findWebApplicationContext(); // if (wac != null) { // this.delegate = initDelegate(wac); // }
2.第一次加載時(shí)去找SpringMVC的IOC容器
①在DelegatingFilterProxy類251行左右進(jìn)行如下修改
//查找IOC容器,優(yōu)先選擇SpringIOC容器,注釋掉,自己寫 //WebApplicationContext wac = findWebApplicationContext(); //1.獲取ServletContext對(duì)象 ServletContext sc = this.getServletContext(); //2.拼接SpringMVC將IOC容器存入ServletContext域的時(shí)候使用的屬性名 String servletName = "springDispatcherServlet"; String attrName =FrameworkServlet.SERVLET_CONTEXT_PREFIX+servletName; //3.根據(jù)attrName從servletContext域中獲取IOC容器 WebApplicationContext wac = (WebApplicationContext) sc.getAttribute(attrName);
最后啟動(dòng)服務(wù)就大功告成了!!!
浙公網(wǎng)安備 33010602011771號(hào)