實驗用到的模板
https://download.csdn.net/download/m2606707610/12122449
已上傳,免費下載。
在上一篇博客中我已經在HelloWorld中導入了該模板,大家可以參考上篇博客,來進行這篇博客的學習。
https://blog.csdn.net/m2606707610/article/details/104099005
第三章 SpringSecurity-實驗
1.實驗一:授權首頁和靜態資源
配置類(AppWebSecurityConfig extends WebSecurityConfigurerAdapter)
重寫configure(HttpSecurity http)方法
@Configuration @EnableWebSecurity public class AppWebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //super.configure(http); //取消默認配置 http.authorizeRequests() .antMatchers("/layui/**","/index.jsp").permitAll() //設置匹配的資源放行 .anyRequest().authenticated(); //剩餘任何資源必須認證 } } |
測試結果
- 靜態資源和index.jsp都可以訪問
- 不存在的資源或有權限但不存在的資源404
3.無權限的資源,403訪問被拒絕
2.實驗二:默認及自定義登錄頁
- 開啓formLogin()功能 ,http.formLogin()
- 靜態資源和index.jsp都可以訪問
- 不存在的資源
http://localhost/spring-security-helloworld/layui/xxx 有權限時,找不到資源會報404錯誤
- 總結:默認表單登錄頁面的規則
1)、自動生成一個登錄頁
2)、登錄請求被默認提交到 /login POST下
3)、生成隱藏域,可以防重複提交和跨站請求僞造;
<input name="_csrf" type="hidden" value="755f0b3c-0965-430b-852e-dcf6c77e7edb" />
爲了測試方便,先禁用這個功能: http.csrf().disable();
4)、默認提交的字段名爲:name='password' name='username'
- 指定登錄頁
- http.formLogin().loginPage("/index.jsp"); //去到指定的登錄頁
- 靜態資源和index.jsp都可以訪問
- 不存在的資源
http.formLogin()//開啓表單登錄功能
.loginPage("/toLogin")//自定義默認登錄頁,這裏toLogin爲轉向自己的登錄頁
.usernameParameter("loginacct")//這裏指定自定義登錄頁的賬號name
.passwordParameter("userpswd")//這裏指定自定義登錄頁的密碼name
.loginProcessingUrl("/doLogin")//這指定的是自定義登錄頁表單提交的action,不指定則默認爲/login
.defaultSuccessUrl("/main");//登陸成功後去到哪個頁面
3.3 實驗三:自定義表單登錄邏輯分析
- 表單提交地址:${PATH }/index.jsp
- 表單提交請求方式:post
- 表單提交請求失敗,提取錯誤消息:${SPRING_SECURITY_LAST_EXCEPTION.message}
- 如何提交表單:
- 引入jquery: <script src="${PATH }/layui/jquery.min.js"></script>
- $("form").submit();
- 表單提交參數名稱: username password
- 提交請求被拒絕
暫時禁用csrf:http.csrf().disable();
- 登錄邏輯分析
/**默認登錄頁面 * /login GET - the login form * /login POST - process the credentials and if valid authenticate the user * /login?error GET - redirect here for failed authentication attempts * /login?logout GET - redirect here after successfully logging out
* 定製登錄頁面:loginPage("/index.jsp"):規定登錄頁的地址在哪裏 * /index.jsp GET - the login form * /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 * ${SPRING_SECURITY_LAST_EXCEPTION.message}可以取出錯誤消息 */ |
- 測試結果
3.4實驗四:自定義認證用戶信息
- 自定義認證用戶信息
|
- CSRF跨站請求僞造
- SpringSecurity添加了csrf功能【DefaultCsrfToken】,所有的表單提交爲了防止跨站請求僞造,我們需要加上_csrf項; 或者,暫時禁用http.csrf().disable();
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
-
- ${_csrf} ===>>> org.springframework.security.web.csrf.DefaultCsrfToken@19116cfd
- <input type="hidden" name="_csrf" value="310988c2-3f9d-4651-9e19-6ef4b2c4aa3a"/>
- 如果不禁用csrf,默認是開啓的狀態;頁面不設置csrf表單域,那麼,提交登錄請求會報錯
- 令牌值變化:
- 如果登錄成功(用戶名,密碼正確),令牌會被刪除,
- 重新回到登錄頁或後退網頁,令牌會重新生成;
- 如果登錄失敗(用戶名,密碼錯誤),令牌不變。
- 刷新登錄頁,令牌值也不變
- 作用:
- 防止別的網站僞造數據,提交請求到我們的網站。
- 擴展-瞭解XSS
- XSS攻擊全稱跨站腳本攻擊,是爲不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫爲XSS,XSS是一種在web應用中的計算機安全漏洞,它允許惡意web用戶將代碼植入到提供給其它用戶使用的頁面中。
- CSRF(Cross-site request forgery)跨站請求僞造,也被稱爲“One Click Attack”或者Session Riding,通常縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站腳本(XSS),但它與XSS非常不同,XSS利用站點內的信任用戶,而CSRF則通過僞裝成受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防範的資源也相當稀少)和難以防範,所以被認爲比XSS更具危險性。
3.5實驗五:用戶註銷完成
- 添加註銷功能(logout)http.logout()默認規則
- /logout:退出系統
- 如果csrf開啓,必須post方式的/logout請求,表單中需要增加csrf token
- logoutUrl();退出系統需要發送的請求,默認爲/logout
- logoutSuccessUrl();退出系統成功以後要跳轉的頁面地址
- addLogoutHandler():自定義註銷處理器
- deleteCookies():指定需要刪除的cookie
- invalidateHttpSession():session失效(DEBUG)
3.6 實驗六:基於角色的訪問控制
- 設置資源可以訪問的角色
http.authorizeRequests().antMatchers("/layui/**","/index.jsp").permitAll() //允許所有人都訪問靜態資源,無論登錄(認證)與否 .antMatchers("/level1/**").hasRole("學徒") .antMatchers("/level2/**").hasRole("大師") .antMatchers("/level3/**").hasRole("宗師") .anyRequest().authenticated(); //放置最後,以上沒有規定的都需要權限認證。 |
- 注意:
- 將.anyRequest().authenticated()錯誤的設置在前面,後面的設置就不起作用了。
- 設置所有,"/**"都可以訪問,其他再進行的設置就不會起作用了
- 設置匿名訪問/level3/** 可以不用登錄,匿名訪問:.anyRequest().anonymous();
- 擁有該角色的資源可以訪問,否則不可以訪問
auth.inMemoryAuthentication() .withUser("zhangsan").password("123456").roles("ADMIN","學徒","宗師") .and() .withUser("自定義訪問拒絕處理頁面,lisi").password("111111").authorities("USER","MANGER"); |
3.7 實驗七:自定義訪問拒絕處理頁面
- 直接增加處理映射界面
http.exceptionHandling().accessDeniedPage("/unauth.html"); |
- 在控制器類中增加映射處理
@RequestMapping("/unauth.html") public String unauth(){ return "unauth"; } |
- 增加顯示頁面,將main.jsp複製,命名爲unauth.jsp,增加一句提示信息
<h1>你無權訪問該頁面...</h1> |
- 測試顯示效果
- 自定義異常處理器
http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { request.setAttribute("message", accessDeniedException.getMessage()); request.getRequestDispatcher("/WEB-INF/views/unauth.jsp").forward(request, response); } }); |
3.8 實驗八:記住我功能
3.8.1 記住我功能-免登錄原理
- http.rememberMe();
- 默認規則
- 頁面checkbox提交remember-me參數
- 默認記住2周登錄狀態:AbstractRememberMeServices
-
- 會在cookie中保存名爲:remember-me的cookie
- 記住了以前登錄的狀態,以後再訪問就不用登錄了
- 登錄後頁面,關閉瀏覽器,直接訪問:
http://localhost/spring-security-helloworld/main.html 可以成功訪問,不必登錄。
- 這種方式,token值是放置在內存中的,服務器端重啓tomcat,token會失效。需要將token記錄在數據庫持久化纔不會失效。
3.8.2 記住我-數據版
- 引入pom.xml 包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.3.20.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!-- mysql驅動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> |
- 配置數據源
<!-- 配置數據源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="root"></property> <property name="password" value="root"></property> <property name="url" value="jdbc:mysql://192.168.137.3:3306/security?useSSL=false"></property> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> </bean> <!-- jdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> |
- 創建表
create table persistent_logins (username varchar(64) not null, series varchar(64) primary key,token varchar(64) not null, last_used timestamp not null) |
- 設置記住我
@Autowired DataSource dataSource;
@Override protected void configure(HttpSecurity http) throws Exception { //。。。 //記住我 JdbcTokenRepositoryImpl ptr = new JdbcTokenRepositoryImpl(); ptr.setDataSource(dataSource); http.rememberMe().tokenRepository(ptr); } |