SpringSecurity概念及整合ssm框架的示例詳解
基本概念
Spring中提供安全認(rèn)證服務(wù)的框架,認(rèn)證:驗(yàn)證用戶密碼是否正確的過(guò)程,授權(quán):對(duì)用戶能訪問(wèn)的資源進(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ò)程中的相關(guān)概念
主體
英文單詞:principal
使用系統(tǒng)的用戶或設(shè)備或從其他系統(tǒng)遠(yuǎn)程登錄的用戶等等。簡(jiǎn)單說(shuō)就是誰(shuí)使用系統(tǒng)誰(shuí)就是主體。
認(rèn)證
英文單詞:authentication
權(quán)限管理系統(tǒng)確認(rèn)一個(gè)主體的身份,允許主體進(jìn)入系統(tǒng)。簡(jiǎn)單說(shuō)就是“主體”證明自己是誰(shuí)?;\統(tǒng)的認(rèn)為就是以前所做的登錄操作。
授權(quán)
英文單詞:authorization
將操作系統(tǒng)的“權(quán)力”“授予”“主體”,這樣主體就具備了操作系統(tǒng)中特定功能的能力。
所以簡(jiǎn)單來(lái)說(shuō),授權(quán)就是給用戶分配權(quán)限。

使用
pom文件中加入spring security的依賴(lài)
<!-- 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>加入配置類(lèi)
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)前類(lèi)是一個(gè)配置類(lèi)
@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()// 允許無(wú)條件訪問(wèn)登錄請(qǐng)求
.antMatchers("/bootstrap/**", "/crowd/**", "/css/**",
"/fonts/**", "/img/**", "/jquery/**", "/layer/**",
"/script/**", "/ztree/**")
.permitAll()// 允許無(wú)條件訪問(wèn)靜態(tài)文件
.antMatchers("/admin/get/page.html")
.hasAuthority("user:get") // 擁有user:get權(quán)限才可以訪問(wèn)用戶維護(hù)
.antMatchers("/role/to/role/page.html")
.hasRole("經(jīng)理")// 擁有經(jīng)理角色才可以訪問(wèn)角色維護(hù)
.antMatchers("/admin/get/page.html")
.access("(hasAnyRole('經(jīng)理')) and hasAuthority('user:get')")
.anyRequest()
.authenticated()// 其他任何資源都要登錄才可以訪問(wèn)
.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()// 開(kāi)啟表單登錄功能
.loginPage("/admin/to/login/page.html")// 設(shè)置默認(rèn)的登錄頁(yè)面
.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")// 退出登錄訪問(wèn)的地址
.logoutSuccessUrl("/admin/to/login/page.html")// 退出頁(yè)面成功要去的地址
;
}
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
// builder
// .inMemoryAuthentication()// 開(kāi)啟內(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)鍵字查詢分頁(yè)信息
*
* @param pageNum 當(dāng)前頁(yè)碼
* @param pageSize 每頁(yè)顯示條數(shù)
* @param keyword 關(guān)鍵字
* @return 分頁(yè)信息
*/
@PreAuthorize("hasAuthority('role:get') or hasAnyRole('經(jīng)理')")// 需要有role:get權(quán)限才可以訪問(wè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
) {
// 獲取頁(yè)面數(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)行比較,如果不一致,則判斷為不能訪問(wèn)。實(shí)現(xiàn)“只能查自己”效果。
@PostAuthorize("returnObject.data.loginAcct == principal.username")使用 returnObject 獲取到方法返回值,使用 principal 獲取到當(dāng)前登錄用戶的主體對(duì)象。
通過(guò)故意寫(xiě)錯(cuò)表達(dá)式,然后從異常信息中發(fā)現(xiàn)表達(dá)式訪問(wèn)的是下面這個(gè)類(lèi)的屬性:
org.springframework.security.access.expression.method.MethodSecurityExpressionRoot
@PreFilter
在方法執(zhí)行前對(duì)傳入的參數(shù)進(jìn)行過(guò)濾。只能對(duì)集合類(lèi)型的數(shù)據(jù)進(jìn)行過(guò)濾。
@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)行過(guò)濾。只能對(duì)集合類(lèi)型的數(shù)據(jù)進(jìn)行過(guò)濾。
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)名稱(chēng)查找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ì)象來(lái)存儲(chǔ)GrantedAuthority
ArrayList<GrantedAuthority> authorities = new ArrayList<>();
// 6、遍歷存入角色消息
for (int i = 0; i < roles.size(); i++) {
// 需要加前綴,因?yàn)镾pringSecurity就是通過(guò)ROLE_來(lái)區(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類(lèi)
SecurityAdmin securityAdmin = new SecurityAdmin(admin, authorities);
return securityAdmin;
}
}
BCryptPasswordEncoder
它是SpringSecurity自帶的密碼加密與驗(yàn)證的類(lèi)。
頁(yè)面元素控制
取出當(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)理')">
<!-- 開(kāi)始和結(jié)束標(biāo)簽之間是要進(jìn)行權(quán)限控制的部分。檢測(cè)當(dāng)前用戶是否有權(quán)限,有權(quán)限
就顯示這里的內(nèi)容,沒(mé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)理')">
<!-- 開(kāi)始和結(jié)束標(biāo)簽之間是要進(jìn)行權(quán)限控制的部分。檢測(cè)當(dāng)前用戶是否有權(quán)限,有權(quán)限
就顯示這里的內(nèi)容,沒(mé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)文章
IDEA之如何關(guān)閉/開(kāi)啟引用提示Usages
這篇文章主要介紹了IDEA之如何關(guān)閉/開(kāi)啟引用提示Usages問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Spring Boot企業(yè)常用的starter示例詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot企業(yè)常用starter的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
springboot網(wǎng)站應(yīng)用使用第三方qq登錄的實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了springboot網(wǎng)站應(yīng)用使用第三方qq登錄,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
spring boot 注冊(cè)攔截器過(guò)程詳解
這篇文章主要介紹了spring boot中注冊(cè)攔截器過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
Mybatis-plus實(shí)現(xiàn)主鍵自增和自動(dòng)注入時(shí)間的示例代碼
這篇文章主要介紹了Mybatis-plus實(shí)現(xiàn)主鍵自增和自動(dòng)注入時(shí)間的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Java最常用的6個(gè)簡(jiǎn)單的計(jì)算題
本篇文章給大家整理的在JAVA中最常用到的簡(jiǎn)單的計(jì)算題,對(duì)此有興趣的朋友可以測(cè)試參考下。2018-02-02

