Spring-Security 简介、入门案例详解、安全框架、权限验证 SSM项目 使用 JavaConfig配置
Spring-Security 簡(jiǎn)介
- 一、介紹
- 二、詳細(xì)步驟
- 1、創(chuàng)建一個(gè)maven項(xiàng)目 添加web 框架。
- 2、導(dǎo)入依賴
- 3、項(xiàng)目整體結(jié)構(gòu)
- 4、Spring 容器配置
- 5、servletContext配置
- 6、加載 Spring容器
- 7、Spring Security初始化
- 8、默認(rèn)根路徑請(qǐng)求
- 8、認(rèn)證頁(yè)面
- 8.1、定制登錄頁(yè)面
- 9、安全配置 WebSecurityConfig
- 10、用戶類
- 11、MyUserDetailsService
- 12、Controller層
- 三、測(cè)試
- 1、認(rèn)證錯(cuò)誤
- 2、認(rèn)證成功
- 3、授權(quán)
- 自言自語(yǔ)
一、介紹
? Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制解決方案的安全框架。它提供了一組可以在Spring應(yīng)用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉(zhuǎn)Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,為應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制功能,減少了為企業(yè)系統(tǒng)安全控制編寫(xiě)大量重復(fù)代碼的工作。
? Spring Security對(duì)Web安全性的支持大量地依賴于Servlet過(guò)濾器。這些過(guò)濾器攔截進(jìn)入請(qǐng)求,并且在應(yīng)用程序處理該請(qǐng)求之前進(jìn)行某些安全處理。 Spring Security提供有若干個(gè)過(guò)濾器,它們能夠攔截Servlet請(qǐng)求,并將這些請(qǐng)求轉(zhuǎn)給認(rèn)證和訪問(wèn)決策管理器處理,從而增強(qiáng)安全性。根據(jù)自己的需要,可以使用適當(dāng)?shù)倪^(guò)濾器來(lái)保護(hù)自己的應(yīng)用程序。
注:這篇不牽扯原理及大量理論知識(shí),只是一個(gè)入門(mén)案例,但是完全足夠大家理解和寫(xiě)簡(jiǎn)單的項(xiàng)目。
二、詳細(xì)步驟
因?yàn)檫@一篇是講spring-security 就是用spring寫(xiě)的 但是我在這篇文章中 并沒(méi)有使用xml配置
全文都是使用javaconfig 進(jìn)行配置的。
1、創(chuàng)建一個(gè)maven項(xiàng)目 添加web 框架。
2、導(dǎo)入依賴
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.4</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-web</artifactId><version>5.3.2.RELEASE</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-config</artifactId><version>5.3.2.RELEASE</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.18</version></dependency></dependencies>3、項(xiàng)目整體結(jié)構(gòu)
4、Spring 容器配置
@Configuration @ComponentScan(basePackages = "com.itheima.security.springmvc" ,excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)}) public class ApplicationConfig { //在此配置除了Controller的其它bean,比如:數(shù)據(jù)庫(kù)鏈接池、事務(wù)管理器、業(yè)務(wù)bean等。 }5、servletContext配置
在config包下定義WebConfig.java,它對(duì)應(yīng)s對(duì)應(yīng)于DispatcherServlet配 置
@Configuration // 相當(dāng)于springmvc 文件 @EnableWebMvc @ComponentScan(basePackages = "com.wyh",includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)}) public class WebConfig implements WebMvcConfigurer {// 視圖解析器@Beanpublic InternalResourceViewResolver viewResolver(){InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setPrefix("/WEB-INF/view/");viewResolver.setSuffix(".jsp");return viewResolver;}// 把根路徑跳轉(zhuǎn)到login上@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("redirect:/login");} }6、加載 Spring容器
在init包下定義Spring容器初始化類SpringApplicationInitializer,此類實(shí)現(xiàn)WebApplicationInitializer接口, Spring容器啟動(dòng)時(shí)加載WebApplicationInitializer接口的所有實(shí)現(xiàn)類 加載 WebSecurityConfig
public class SpringApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {// spring 容器@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[]{ ApplicationConfig.class , WebSecurityConfig.class};}//servletContext@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{WebConfig.class};}//url-mapping@Overrideprotected String[] getServletMappings() {return new String[]{"/"};} }7、Spring Security初始化
Spring Security初始化,這里有兩種情況
若當(dāng)前環(huán)境沒(méi)有使用Spring或Spring MVC,則需要將 WebSecurityConfig(Spring Security配置類) 傳入超 類,以確保獲取配置,并創(chuàng)建spring context。
相反,若當(dāng)前環(huán)境已經(jīng)使用spring,我們應(yīng)該在現(xiàn)有的springContext中注冊(cè)Spring Security(上一步已經(jīng)做將 WebSecurityConfig加載至rootcontext),此方法可以什么都不做。 在init包下定義SpringSecurityApplicationInitializer:
public class SpringSecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {public SpringSecurityApplicationInitializer(){}}8、默認(rèn)根路徑請(qǐng)求
默認(rèn)根路徑請(qǐng)求 在WebConfig.java中添加默認(rèn)請(qǐng)求根路徑跳轉(zhuǎn)到/login,此url為spring security提供:
@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("redirect:/login"); // registry.addViewController("/login-view").setViewName("login");}8、認(rèn)證頁(yè)面
因?yàn)檫@次只是寫(xiě)一個(gè)入門(mén)案例 頁(yè)面就沒(méi)有額外寫(xiě)了 但是怎么設(shè)置還是有說(shuō)滴。
默認(rèn)認(rèn)證頁(yè)面
8.1、定制登錄頁(yè)面
8.1.1、 在config包WebConfig.java中
//默認(rèn)Url根路徑跳轉(zhuǎn)到/login,此url為spring security提供 @Override public void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("redirect:/login‐view");registry.addViewController("/login‐view").setViewName("login"); }8.1.2、在WebSecurityConfig.java中 增加配置
@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable() // 關(guān)閉csrf.authorizeRequests().antMatchers("/r/r1").hasAnyAuthority("p1")// 表示:訪問(wèn)/r/r1資源的 url需要擁有p1權(quán)限。.antMatchers("/r/r2").hasAnyAuthority("p2").antMatchers("/r/**").authenticated() // 訪問(wèn)/r/下所有請(qǐng)求都需要通過(guò)身份認(rèn)證.anyRequest().permitAll() //指定任何人都允許使用URL.and().formLogin() // 支持form表單認(rèn)證,認(rèn)證成功后轉(zhuǎn)向/login-success。.loginPage("/login‐view") //1.loginProcessingUrl("/login")// 2.successForwardUrl("/login-success") // 自定義登錄成功的配置 認(rèn)證通過(guò)后跳轉(zhuǎn)到login-success.permitAll(); //3}1、指定我們自己的登錄頁(yè),spring security以重定向方式跳轉(zhuǎn)到/login-view
2、指定登錄處理的URL,也就是用戶名、密碼表單提交的目的路徑
3、我們必須允許所有用戶訪問(wèn)我們的登錄頁(yè)(例如為驗(yàn)證的用戶),這個(gè) formLogin().permitAll() 方法允許 任意用戶訪問(wèn)基于表單登錄的所有的URL。
9、安全配置 WebSecurityConfig
spring security提供了用戶名密碼登錄、退出、會(huì)話管理等認(rèn)證功能,只需要配置即可使用。
在config包下定義WebSecurityConfig,安全配置的內(nèi)容包括:用戶信息、密碼編碼器、安全攔截機(jī)制。
@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Bean //密碼編碼器、public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Override //安全攔截機(jī)制。protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/r/r1").hasAnyAuthority("p1") // 訪問(wèn)/r/r1 需要有p1權(quán)限 下同.antMatchers("/r/r2").hasAnyAuthority("p2").antMatchers("/r/**").authenticated() // 訪問(wèn)/r/下所有請(qǐng)求都需要通過(guò)身份認(rèn)證.anyRequest().permitAll() //指定任何人都允許使用URL.and().formLogin() // 支持form表單認(rèn)證,認(rèn)證成功后轉(zhuǎn)向/login-success。.successForwardUrl("/login-success"); // 自定義登錄成功的配置} }10、用戶類
@Data @AllArgsConstructor @NoArgsConstructor public class MyUser{private Integer id;private String username;private String password; }11、MyUserDetailsService
在MyUserDetailsService()方法中,我們返回了一個(gè)UserDetailsService給spring容器,Spring Security會(huì)使用它來(lái) 獲取用戶信息
今天是初使用 不寫(xiě)多了…。
@Component public class MyUserDetailsService implements UserDetailsService {@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 登錄賬號(hào)// 這里是模擬數(shù)據(jù)庫(kù)查詢MyUser myUser = getUserByName(username);if (myUser== null) {return null;}//創(chuàng)建userDetailsUserDetails userDetails =User.withUsername(myUser.getUsername()).password(BCrypt.hashpw(myUser.getPassword(),BCrypt.gensalt())).authorities("p1").build();// pssword() 使用了密碼加密 加密方式在之前講了。 // 數(shù)據(jù)庫(kù)里的密碼是不會(huì)存明文密碼 這里也是在模擬。// 因?yàn)槲沂褂昧嗣艽a加密 我登錄輸入的密碼 // security 在處理的時(shí)候 也會(huì)進(jìn)行加密 然后再比對(duì)。return userDetails;}private MyUser getUserByName(String username){return new MyUser(1,username,"123456");} }12、Controller層
測(cè)試的請(qǐng)求
@RestController public class LoginController {@RequestMapping(value = "/login-success", produces = "text/plain;charset=utf-8")public String loginSuccess(){return getUsername()+"登錄成功";}@RequestMapping(value = "/r/r1", produces = "text/plain;charset=utf-8")public String r1(){return getUsername()+"資源1";}@RequestMapping(value = "/r/r2", produces = "text/plain;charset=utf-8")public String r2(){return getUsername()+"資源2";}// 這個(gè)權(quán)限是 身份驗(yàn)證通過(guò)就可以訪問(wèn)的 不要用戶有權(quán)限的。@RequestMapping(value = "/r/r3", produces = "text/plain;charset=utf-8")public String r3(){return getUsername()+"這個(gè)用戶是沒(méi)有任何權(quán)限 這個(gè)請(qǐng)求也只要登錄驗(yàn)證就可"+ " 資源3";}private String getUsername(){String username=null;//當(dāng)前通過(guò)的用戶身份Authentication authentication = SecurityContextHolder.getContext().getAuthentication();Object principal = authentication.getPrincipal();if (principal==null){username="匿名";}if(principal instanceof UserDetails){UserDetails userDetails= (UserDetails)principal;username = userDetails.getUsername();}else{username= principal.toString();}return username;} }三、測(cè)試
1、認(rèn)證錯(cuò)誤
當(dāng)輸入錯(cuò)誤的密碼的時(shí)候 會(huì)自動(dòng)彈出提示。
2、認(rèn)證成功
當(dāng)用戶名和密碼都輸入正確的時(shí)候 它就會(huì)跳轉(zhuǎn)到 /login-success請(qǐng)求去
3、授權(quán)
當(dāng)我們的用戶有權(quán)限的時(shí)候 就是用我現(xiàn)在模擬的數(shù)據(jù)(username:admin password:123456 p1 權(quán)限)
來(lái)訪問(wèn) /r/r1
接下來(lái)接著訪問(wèn) /r/r2 /r/r2 是需要p2權(quán)限 模擬的數(shù)據(jù)是沒(méi)有這個(gè)權(quán)限
會(huì)報(bào) 403 錯(cuò)誤 權(quán)限不足。
在 /r/** 下 所有用戶都需要身份驗(yàn)證通過(guò)才可以訪問(wèn)的。
如果在沒(méi)有登錄的情況下 訪問(wèn) /r/r3 是會(huì)自動(dòng)轉(zhuǎn)到登錄頁(yè)面去。
自言自語(yǔ)
今天是做了一個(gè)security 的入門(mén)案例 。
今天比平時(shí)寫(xiě)的時(shí)間還長(zhǎng)一些。
看完的話 最基本的是可以用了 那里面的數(shù)據(jù) 是可以從數(shù)據(jù)庫(kù)里面查詢的。
權(quán)限表的設(shè)計(jì) 在我之前一篇博客已經(jīng)發(fā)出來(lái)了。
RBAC、控制權(quán)限設(shè)計(jì)、權(quán)限表設(shè)計(jì)
等過(guò)幾天把springboot-security 的案例也寫(xiě)出來(lái)
那個(gè)是從數(shù)據(jù)庫(kù)查詢的,不再是模擬數(shù)據(jù)拉。
繼續(xù)。
總結(jié)
以上是生活随笔為你收集整理的Spring-Security 简介、入门案例详解、安全框架、权限验证 SSM项目 使用 JavaConfig配置的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: RBAC、控制权限设计、权限表设计 基于
- 下一篇: SpringBoot-Security