SpringSecurity概念及整合ssm框架的示例詳解
基本概念
Spring中提供安全認(rèn)證服務(wù)的框架,認(rèn)證:驗(yàn)證用戶密碼是否正確的過程,授權(quán):對(duì)用戶能訪問的資源進(jìn)行控制

用戶登錄系統(tǒng)時(shí)我們協(xié)助 SpringSecurity 把用戶對(duì)應(yīng)的角色、權(quán)限組裝好,同時(shí)把各個(gè)資源所要求的權(quán)限信息設(shè)定好,剩下的“登錄驗(yàn)證”、“權(quán)限驗(yàn)證”等等工作都交給SpringSecurity。
權(quán)限管理過程中的相關(guān)概念
主體
英文單詞:principal
使用系統(tǒng)的用戶或設(shè)備或從其他系統(tǒng)遠(yuǎn)程登錄的用戶等等。簡(jiǎn)單說就是誰使用系統(tǒng)誰就是主體。
認(rèn)證
英文單詞:authentication
權(quán)限管理系統(tǒng)確認(rèn)一個(gè)主體的身份,允許主體進(jìn)入系統(tǒng)。簡(jiǎn)單說就是“主體”證明自己是誰?;\統(tǒng)的認(rèn)為就是以前所做的登錄操作。
授權(quán)
英文單詞:authorization
將操作系統(tǒng)的“權(quán)力”“授予”“主體”,這樣主體就具備了操作系統(tǒng)中特定功能的能力。
所以簡(jiǎn)單來說,授權(quán)就是給用戶分配權(quán)限。

使用
pom文件中加入spring security的依賴
<!-- SpringSecurity 對(duì) Web 應(yīng)用進(jìn)行權(quán)限管理 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.2.10.RELEASE</version> </dependency> <!-- SpringSecurity 配置 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.2.10.RELEASE</version> </dependency> <!-- SpringSecurity 標(biāo)簽庫(kù) --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>4.2.10.RELEASE</version> </dependency>
web.xml加入SpringSecurity控制權(quán)限的Filte
<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>加入配置類
package com.atguigu.crowd.mvc.config;
import com.atguigu.crowd.constant.CrowdConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration// 表示當(dāng)前類是一個(gè)配置類
@EnableWebSecurity// 啟用web環(huán)境下權(quán)限控制
// prePostEnabled = true的作用:保證@PreAuthorize、@PreAuthorize、@PreFilter、@PostFilter生效
@EnableGlobalMethodSecurity(prePostEnabled = true)// 啟用全局方法權(quán)限控制
public class WebApplicationConfig extends WebSecurityConfigurerAdapter {
@Autowired
CrowdUserDetailsService crowdUserDetailsService;
@Autowired
BCryptPasswordEncoder passwordEncoder;
@Override
protected void configure(HttpSecurity security) throws Exception {
security
.authorizeRequests()
.antMatchers("/admin/to/login/page.html")
.permitAll()// 允許無條件訪問登錄請(qǐng)求
.antMatchers("/bootstrap/**", "/crowd/**", "/css/**",
"/fonts/**", "/img/**", "/jquery/**", "/layer/**",
"/script/**", "/ztree/**")
.permitAll()// 允許無條件訪問靜態(tài)文件
.antMatchers("/admin/get/page.html")
.hasAuthority("user:get") // 擁有user:get權(quán)限才可以訪問用戶維護(hù)
.antMatchers("/role/to/role/page.html")
.hasRole("經(jīng)理")// 擁有經(jīng)理角色才可以訪問角色維護(hù)
.antMatchers("/admin/get/page.html")
.access("(hasAnyRole('經(jīng)理')) and hasAuthority('user:get')")
.anyRequest()
.authenticated()// 其他任何資源都要登錄才可以訪問
.and()
.exceptionHandling()
.accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
request.setAttribute("exception", new
Exception(CrowdConstant.MESSAGE_ACCESS_DENIED));
request.getRequestDispatcher("/WEB-INF/error/system_error.jsp").forward(request, response);
}
})// 出現(xiàn)異常的處理方法
.and()
.csrf()
.disable()// 禁用跨站請(qǐng)求偽造功能
.formLogin()// 開啟表單登錄功能
.loginPage("/admin/to/login/page.html")// 設(shè)置默認(rèn)的登錄頁面
.loginProcessingUrl("/security/do/login.html")// 處理登錄請(qǐng)求的地址
.defaultSuccessUrl("/admin/to/admin-main/page.html")// 登錄成功后要前往的地址
.usernameParameter("loginAcct")// 賬號(hào)的請(qǐng)求參數(shù)名
.passwordParameter("userPswd")// 密碼的請(qǐng)求參數(shù)名
.and()
.logout()
.logoutUrl("/security/do/logout.html")// 退出登錄訪問的地址
.logoutSuccessUrl("/admin/to/login/page.html")// 退出頁面成功要去的地址
;
}
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
// builder
// .inMemoryAuthentication()// 開啟內(nèi)存認(rèn)證
// .withUser("tom")// 設(shè)置賬號(hào)
// .password("123123")// 設(shè)置密碼
// .roles("ADMIN")// 設(shè)置角色
// ;
// 使用基于數(shù)據(jù)庫(kù)的認(rèn)證
builder.userDetailsService(crowdUserDetailsService).passwordEncoder(passwordEncoder);
}
}
注解@PreAuthorize規(guī)定角色權(quán)限
需要在SpringSecurity中標(biāo)注
@EnableGlobalMethodSecurity(prePostEnabled = true)
/**
* 根據(jù)關(guān)鍵字查詢分頁信息
*
* @param pageNum 當(dāng)前頁碼
* @param pageSize 每頁顯示條數(shù)
* @param keyword 關(guān)鍵字
* @return 分頁信息
*/
@PreAuthorize("hasAuthority('role:get') or hasAnyRole('經(jīng)理')")// 需要有role:get權(quán)限才可以訪問
@ResponseBody
@GetMapping("/role/get/page/info.json")
public ResultEntity<PageInfo<Role>> getPageInfo(
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "4") Integer pageSize,
@RequestParam(value = "keyword", defaultValue = "") String keyword
) {
// 獲取頁面數(shù)據(jù)
PageInfo<Role> pageInfo = roleService.getRoleByKeyword(pageNum, pageSize, keyword);
// 如果出現(xiàn)異常,dispatcherServlet會(huì)進(jìn)行處理
return ResultEntity.successWithData(pageInfo);
}
@PostAuthorize
先執(zhí)行方法然后根據(jù)方法返回值判斷是否具備權(quán)限。
例如:查詢一個(gè) Admin 對(duì)象,在@PostAuthorize 注解中和當(dāng)前登錄的 Admin 對(duì)象進(jìn)行比較,如果不一致,則判斷為不能訪問。實(shí)現(xiàn)“只能查自己”效果。
@PostAuthorize("returnObject.data.loginAcct == principal.username")使用 returnObject 獲取到方法返回值,使用 principal 獲取到當(dāng)前登錄用戶的主體對(duì)象。
通過故意寫錯(cuò)表達(dá)式,然后從異常信息中發(fā)現(xiàn)表達(dá)式訪問的是下面這個(gè)類的屬性:
org.springframework.security.access.expression.method.MethodSecurityExpressionRoot
@PreFilter
在方法執(zhí)行前對(duì)傳入的參數(shù)進(jìn)行過濾。只能對(duì)集合類型的數(shù)據(jù)進(jìn)行過濾。
@PreFilter(value="filterObject%2==0")
@ResponseBody
@RequestMapping("/admin/test/pre/filter")
public ResultEntity<List<Integer>> saveList(@RequestBody List<Integer> valueList) {
return ResultEntity.successWithData(valueList);
}@PostFilter
在方法執(zhí)行后對(duì)方法返回值進(jìn)行過濾。只能對(duì)集合類型的數(shù)據(jù)進(jìn)行過濾。
CrowdUserDetailsService
其實(shí)返回的就是SpringSecurity的User對(duì)象,只是做了一層封裝。
package com.atguigu.crowd.mvc.config;
import com.atguigu.crowd.entity.Admin;
import com.atguigu.crowd.entity.Role;
import com.atguigu.crowd.service.api.AdminService;
import com.atguigu.crowd.service.api.AuthService;
import com.atguigu.crowd.service.api.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class CrowdUserDetailsService implements UserDetailsService {
@Autowired
private AdminService adminService;
@Autowired
private RoleService roleService;
@Autowired
private AuthService authService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 1、根據(jù)賬號(hào)名稱查找Admin對(duì)象
Admin admin = adminService.getAdminByLoginAcct(username);
// 2、獲取adminId
Integer adminId = admin.getId();
// 3、根據(jù)adminId查詢角色信息
List<Role> roles = roleService.getAssignedRole(adminId);
// 4、根據(jù)adminId查詢權(quán)限名字信息
List<String> auths = authService.getAssignedAuthNameByAdminId(adminId);
// 5、創(chuàng)建集合對(duì)象來存儲(chǔ)GrantedAuthority
ArrayList<GrantedAuthority> authorities = new ArrayList<>();
// 6、遍歷存入角色消息
for (int i = 0; i < roles.size(); i++) {
// 需要加前綴,因?yàn)镾pringSecurity就是通過ROLE_來區(qū)分是角色還是權(quán)限
String roleName = "ROLE_" + roles.get(i).getName();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(roleName);
authorities.add(authority);
}
// 7、遍歷存入權(quán)限信息
for (int i = 0; i < auths.size(); i++) {
String authName = auths.get(i);
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(authName);
authorities.add(authority);
}
// 8、封裝到SecurityAdmin對(duì)象中,它繼承了SpringSecurity的User類
SecurityAdmin securityAdmin = new SecurityAdmin(admin, authorities);
return securityAdmin;
}
}
BCryptPasswordEncoder
它是SpringSecurity自帶的密碼加密與驗(yàn)證的類。
頁面元素控制
取出當(dāng)前登錄對(duì)象
<%--需要導(dǎo)入taglib--%> <%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %> <%--principal 是我們自己封裝的 SecurityAdmin 對(duì)象(返回的SpringSecurity的User對(duì)象)--%> <security:authentication property="principal.originalAdmin.userName"/>
標(biāo)簽庫(kù)控制
<%--需要導(dǎo)入taglib--%>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %>
<security:authorize access="hasRole('經(jīng)理')">
<!-- 開始和結(jié)束標(biāo)簽之間是要進(jìn)行權(quán)限控制的部分。檢測(cè)當(dāng)前用戶是否有權(quán)限,有權(quán)限
就顯示這里的內(nèi)容,沒有權(quán)限就不顯示。 --> ……
</security:authorize>access屬性可以傳入權(quán)限控制相關(guān)的表達(dá)式。
### 標(biāo)簽庫(kù)控制
```html
<%--需要導(dǎo)入taglib--%>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %>
<security:authorize access="hasRole('經(jīng)理')">
<!-- 開始和結(jié)束標(biāo)簽之間是要進(jìn)行權(quán)限控制的部分。檢測(cè)當(dāng)前用戶是否有權(quán)限,有權(quán)限
就顯示這里的內(nèi)容,沒有權(quán)限就不顯示。 --> ……
</security:authorize>access屬性可以傳入權(quán)限控制相關(guān)的表達(dá)式。
到此這篇關(guān)于SpringSecurity概念以及整合ssm框架的文章就介紹到這了,更多相關(guān)SpringSecurity整合ssm框架內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
我總結(jié)的幾種@Transactional失效原因說明
這篇文章主要是我總結(jié)的幾種@Transactional失效原因說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
springboot啟動(dòng)加載CommandLineRunner @PostConstruct問題
這篇文章主要介紹了springboot啟動(dòng)加載CommandLineRunner @PostConstruct問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
idea 右鍵項(xiàng)目沒有run 運(yùn)行選項(xiàng)
這篇文章主要介紹了idea 右鍵項(xiàng)目沒有run 運(yùn)行選項(xiàng),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
Java中RSA加密解密的實(shí)現(xiàn)方法分析
這篇文章主要介紹了Java中RSA加密解密的實(shí)現(xiàn)方法,結(jié)合具體實(shí)例形式分析了java實(shí)現(xiàn)RSA加密解密算法的具體步驟與相關(guān)操作技巧,并附帶了關(guān)于RSA算法密鑰長(zhǎng)度/密文長(zhǎng)度/明文長(zhǎng)度的參考說明,需要的朋友可以參考下2017-07-07
Spring IOC簡(jiǎn)單理解及創(chuàng)建對(duì)象的方式
這篇文章主要介紹了Spring IOC簡(jiǎn)單理解及創(chuàng)建對(duì)象的方式,本文通過兩種方式給大家介紹創(chuàng)建對(duì)象的方法,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09
JAVA中JSONObject對(duì)象和Map對(duì)象之間的相互轉(zhuǎn)換
這篇文章主要介紹了JAVA中JSONObject對(duì)象和Map對(duì)象之間的相互轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
MybatisPlus 不修改全局策略和字段注解如何將字段更新為null
這篇文章主要介紹了MybatisPlus 不修改全局策略和字段注解如何將字段更新為null,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
java Socket實(shí)現(xiàn)簡(jiǎn)單模擬HTTP服務(wù)器
這篇文章主要介紹了java Socket實(shí)現(xiàn)簡(jiǎn)單模擬HTTP服務(wù)器,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05

