欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解析spring-security權(quán)限控制和校驗(yàn)的問題

 更新時(shí)間:2021年03月16日 14:40:34   作者:terry2870  
這篇文章主要介紹了解析spring-security權(quán)限控制和校驗(yàn)的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

前言

    在我們項(xiàng)目中經(jīng)常會(huì)涉及到權(quán)限管理,特別是一些企業(yè)級(jí)后臺(tái)應(yīng)用中,那權(quán)限管理是必不可少的。這個(gè)時(shí)候就涉及到技術(shù)選型的問題。在我以前項(xiàng)目中也沒用到什么權(quán)限框架,就全部到一個(gè)spring mvc攔截器中去校驗(yàn)權(quán)限,當(dāng)然,對(duì)需求比較少,小型的項(xiàng)目這也不失一個(gè)好的實(shí)現(xiàn)(實(shí)現(xiàn)簡(jiǎn)單,功能單一),但是對(duì)于一些比較大的應(yīng)用,權(quán)限認(rèn)證,session管理要求比較高的項(xiàng)目,如果再使用mvc攔截器,那就得不償失了(需要自己去實(shí)現(xiàn)很多的代碼)。
    現(xiàn)在比較流行的權(quán)限校驗(yàn)框架有spring-security 和 apache-shiro。鑒于我們一直在使用spring全家桶,那我的項(xiàng)目中當(dāng)然首選spring-security。下面我我所認(rèn)識(shí)的spring-security來一步一步的看怎么實(shí)現(xiàn)。這里我拋磚引玉,歡迎大家指正。

我的完整代碼在我的github中 我的github ,歡迎大家留言討論?。?/p>


一、spring-security是什么?

    Spring Security 是 Spring 家族中的一個(gè)安全管理框架,類似的安全框架還有apache-shiro。shiro以使用簡(jiǎn)單,功能強(qiáng)大而著稱,本篇我們只討論Spring Security,shiro就不再鋪開討論了。
    以前我們?cè)谑褂胹pringMVC與Security 結(jié)合的時(shí)候,那一堆堆配置文件,長(zhǎng)篇大論的xml看的人頭大,幸好,現(xiàn)在有了springboot,可以基于java config的方式配置,實(shí)現(xiàn)零配置,而且又兼有springboot的約定大于配置的前提,我們項(xiàng)目中的配置文件或需要配置的代碼大大減少了。

二、spring-security能為我們做什么?

spring-security最主要的功能包含:
1、認(rèn)證(就是,你是誰)
2、授權(quán)(就是,你能干什么)
3、攻擊防護(hù) (防止偽造身份)
這三點(diǎn)其實(shí)就是我們?cè)趹?yīng)用中常用到的?,F(xiàn)在有了spring-security框架,就使得我們代碼實(shí)現(xiàn)起來非常簡(jiǎn)單。

下面就來跟著我一步一步來看,怎么使用它

三、使用步驟

1.maven依賴

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

版本號(hào)就跟著springboot版本走

2.application.properties文件

server.port=8080
server.servlet.context-path=/demo

spring.main.allow-bean-definition-overriding=true
spring.profiles.active=dev

這個(gè)時(shí)候,我們啟動(dòng)項(xiàng)目,就會(huì)在控制臺(tái)看到這一行信息

紅色框出來的就是spring-security為你自動(dòng)分配的賬號(hào)為 user 的密碼。

3.訪問接口

    你現(xiàn)在如果想要訪問系統(tǒng)里面的接口,那必須要經(jīng)過這個(gè)權(quán)限驗(yàn)證。
隨便打開一個(gè)接口都會(huì)跳轉(zhuǎn)到內(nèi)置的一個(gè)登陸頁(yè)面中

    我們看到,他跳轉(zhuǎn)到一個(gè)地址為login的頁(yè)面去了。這個(gè)時(shí)候我們輸入用戶名 user,密碼為控制臺(tái)打印出來的一串字符, 點(diǎn)擊按鈕 sign in 頁(yè)面正常跳轉(zhuǎn)到接口返回的數(shù)據(jù)。
我們發(fā)現(xiàn),我們沒有寫一行代碼,僅僅是在pom里面依賴了spring-boot-starter-security,框架就自動(dòng)為我們做了最簡(jiǎn)單的驗(yàn)證功能,驚不驚喜意不意外。當(dāng)然僅僅這么點(diǎn)當(dāng)然不能滿足我們項(xiàng)目的要求,不急,聽我一步一步慢慢道來。

4.功能進(jìn)階

下面我們以最常見的企業(yè)級(jí)應(yīng)用管理后臺(tái)的權(quán)限為例
我們需要提出幾個(gè)問題
1、用戶的賬號(hào),密碼保存在數(shù)據(jù)庫(kù)中,登錄的時(shí)候驗(yàn)證
2、用戶登錄成功后,每訪問一個(gè)地址,后臺(tái)都要判斷該用戶有沒有這個(gè)菜單的權(quán)限,有,則放行;沒有,則,拒絕訪問。
3、系統(tǒng)中的一些靜態(tài)資源則直接放行,不需要經(jīng)過權(quán)限校驗(yàn)
4、系統(tǒng)中可能存在三種類型的資源地址
    ①:所有用戶都能訪問的地址(如:登錄頁(yè)面)
    ②:只要登錄,就可以訪問的地址(如:首頁(yè))
    ③:需要授權(quán)才能訪問的地址

    針對(duì)上面提出的幾個(gè)問題,我們?cè)O(shè)計(jì)最常用的權(quán)限表結(jié)構(gòu)模型

sys_user(用戶表:保存用戶的基本信息,登錄名,密碼等等)sys_role(角色表:保存了創(chuàng)建的角色)sys_menu(菜單表:保存了系統(tǒng)可訪問的資源(包含菜單url等))sys_user_role(用戶關(guān)聯(lián)的角色:一個(gè)用戶可以關(guān)聯(lián)多個(gè)角色,最后用戶的權(quán)限就是這多個(gè)角色權(quán)限的并集)sys_role_menu(角色關(guān)聯(lián)的菜單:一個(gè)角色可以關(guān)聯(lián)多個(gè)菜單) 5.spring-security主配置類

    spring-security的主配置類,就需要我們自定義一個(gè)類繼承 WebSecurityConfigurerAdapter 并且實(shí)現(xiàn)里面方法,如下:

package com.hp.springboot.admin.security;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.hp.springboot.admin.constant.AdminConstants;
import com.hp.springboot.admin.interceptor.UrlAuthenticationInterceptor;
import com.hp.springboot.admin.security.handler.AdminAccessDeniedHandler;
import com.hp.springboot.admin.security.handler.AdminAuthenticationEntryPoint;
import com.hp.springboot.admin.security.handler.AdminAuthenticationFailureHandler;
import com.hp.springboot.admin.security.handler.AdminAuthenticationSuccessHandler;
import com.hp.springboot.common.configuration.CommonWebMvcConfigurer;

/**
 1. 描述:security全局配置
 2. 作者:黃平
 3. 時(shí)間:2021年1月11日
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) //開啟Security注解的功能,如果你項(xiàng)目中不用Security的注解(hasRole,hasAuthority等),則可以不加該注解
public class AdminWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private CommonWebMvcConfigurer commonWebMvcConfigurer;
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		// 設(shè)置超級(jí)管理員
		auth.inMemoryAuthentication()
			.withUser(AdminConstants.ADMIN_USER)
		;
		
		// 其余賬號(hào)通過數(shù)據(jù)庫(kù)查詢驗(yàn)證
		auth.userDetailsService(adminUserDetailsService()).passwordEncoder(passwordEncoder());
	}
	
	@Override
	public void configure(WebSecurity web) throws Exception {
		// 靜態(tài)資源
		String[] ignoreArray = commonWebMvcConfigurer.getMergeStaticPatternArray();
		
		// 設(shè)置系統(tǒng)的靜態(tài)資源。靜態(tài)資源不會(huì)走權(quán)限框架
		web.ignoring().antMatchers(ignoreArray);
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 驗(yàn)證碼過濾器
		http.addFilterBefore(new ValidateCodeFilter(), UsernamePasswordAuthenticationFilter.class);
		
		// 第一層免過濾列表
		// 就是所有人都可以訪問的地址。區(qū)別于靜態(tài)資源
		List<String> noFilterList = new ArrayList<>();
		noFilterList.add(AdminConstants.ACCESS_DENIED_URL);
		noFilterList.add(AdminConstants.VERIFY_CODE_URL);
		noFilterList.addAll(commonWebMvcConfigurer.getMergeFirstNoFilterList());
				
		http.formLogin()// 登錄頁(yè)面使用form提交的方式
		.usernameParameter("username").passwordParameter("password")// 設(shè)置登錄頁(yè)面用戶名和密碼的input對(duì)應(yīng)name值(其實(shí)默認(rèn)值就是username,password,所以這里可以不用設(shè)置)
		.loginPage(AdminConstants.LOGIN_PAGE_URL)// 設(shè)置登錄頁(yè)面的地址
		.loginProcessingUrl(AdminConstants.LOGIN_PROCESSING_URL)// 登錄頁(yè)面輸入用戶名密碼后提交的地址
		.successHandler(adminAuthenticationSuccessHandler())// 登錄成功處理
		.failureHandler(adminAuthenticationFailureHandler())// 登錄失敗的處理
		.permitAll()// 以上url全部放行,不需要校驗(yàn)權(quán)限
		.and()
		
		// 注銷相關(guān)配置
		.logout()
		.logoutUrl(AdminConstants.LOGOUT_URL)// 注銷地址
		.logoutSuccessUrl(AdminConstants.LOGIN_PAGE_URL)// 注銷成功后跳轉(zhuǎn)地址(這里就是跳轉(zhuǎn)到登錄頁(yè)面)
		.permitAll()// 以上地址全部放行
		.and().authorizeRequests()
		
		// 第一層免過濾列表
		// 不需要登錄,就可以直接訪問的地址
		.antMatchers(noFilterList.toArray(new String[noFilterList.size()])).permitAll() // 全部放行
		
		// 其他都需要權(quán)限控制
		// 這里使用.anyRequest().access方法,把權(quán)限驗(yàn)證交給指定的一個(gè)方法去處理。
		// 這里 hasPermission接受兩個(gè)參數(shù)request和authentication
		.anyRequest().access("@UrlAuthenticationInterceptor.hasPermission(request, authentication)")
		
		// 異常處理
		.and().exceptionHandling()
		.accessDeniedHandler(new AdminAccessDeniedHandler())// 登錄用戶訪問無權(quán)限的資源
		.authenticationEntryPoint(new AdminAuthenticationEntryPoint())// 匿名用戶訪問無權(quán)限的資源
		.and().csrf().disable()// 禁用csrf
		
		// session管理
		.sessionManagement()
		.invalidSessionUrl(AdminConstants.LOGIN_PAGE_URL)// session失效后,跳轉(zhuǎn)的地址
		.maximumSessions(1)// 同一個(gè)賬號(hào)最大允許同時(shí)在線數(shù)
		;
	}
	
	/**
	 * @Title: passwordEncoder
	 * @Description: 加密方式
	 * @return
	 */
	@Bean
 public PasswordEncoder passwordEncoder() {
  return new BCryptPasswordEncoder();
 }
	
	/**
	 * @Title: adminUserDetailsService
	 * @Description: 用戶信息
	 * @return
	 */
	@Bean
	public UserDetailsService adminUserDetailsService() {
		return new AdminUserDetailsService();
	}
	
	/**
	 * d
	 * @Title: adminAuthenticationFailureHandler
	 * @Description: 登錄異常處理
	 * @return
	 */
	@Bean
	public AdminAuthenticationFailureHandler adminAuthenticationFailureHandler() {
		return new AdminAuthenticationFailureHandler();
	}
	
	/**
	 * @Title: adminAuthenticationSuccessHandler
	 * @Description: 登錄成功后的處理
	 * @return
	 */
	@Bean
	public AdminAuthenticationSuccessHandler adminAuthenticationSuccessHandler() {
		return new AdminAuthenticationSuccessHandler();
	}
	
	/**
	 * @Title: urlAuthenticationInterceptor
	 * @Description: 查詢權(quán)限攔截器
	 * @return
	 */
	@Bean("UrlAuthenticationInterceptor")
	public UrlAuthenticationInterceptor urlAuthenticationInterceptor() {
		return new UrlAuthenticationInterceptor();
	}
}

解讀一下這個(gè)類:

類繼承WebSecurityConfigurerAdapter 說明是一個(gè)spring-Security配置類注解 @Configuration 說明是一個(gè)springboot的配置類注解 @EnableGlobalMethodSecurity 不是必須。開啟注解用的第一個(gè) configure 方法,設(shè)置登錄的用戶和賬號(hào)驗(yàn)證方法
    這里設(shè)置了兩種方式,一個(gè)是內(nèi)置的admin賬號(hào),一個(gè)是通過數(shù)據(jù)庫(kù)驗(yàn)證賬號(hào)
    這樣設(shè)置有個(gè)好處,就是我們?cè)诤笈_(tái)的用戶管理頁(yè)面里面是看不到admin賬號(hào)的,這樣就不會(huì)存在把所有用戶都刪除了,就登錄不了系統(tǒng)的bug(好多年前做系統(tǒng)的時(shí)候,一個(gè)測(cè)試人員一上來就打開用戶管理菜單,然后把所有用戶都刪除,再退出。然后就登錄不了系統(tǒng)了,隨即提了一個(gè)bug。只能手動(dòng)插入數(shù)據(jù)到數(shù)據(jù)庫(kù)才行,當(dāng)時(shí)我看的一臉懵逼,還能這樣操作???)。現(xiàn)在有了這樣設(shè)置,就保證admin用戶永遠(yuǎn)不可能被刪除,也就不存在上面提到的bug了。第二個(gè)configure方法。這個(gè)方法是設(shè)置一些靜態(tài)資源的。可以在這里設(shè)置系統(tǒng)所有的靜態(tài)資源第三個(gè)configure方法。這個(gè)是這個(gè)類中最重要的配置。里面設(shè)置了登錄方式、url過濾規(guī)則、權(quán)限校驗(yàn)規(guī)則、成功處理、失敗處理、session管理、登出處理等等。這里是鏈?zhǔn)降恼{(diào)用方式,可以把需要的都在里面配置

這里有幾個(gè)特別要說明的:
1、我們項(xiàng)目中保存到session中的用戶對(duì)象一般是我們項(xiàng)目中自定義的一個(gè)類(我這里是SysUserResponseBO),在項(xiàng)目中我們用 SecurityContextHolder.getContext().getAuthentication().getPrincipal() 這個(gè)方法獲取當(dāng)前登錄用戶信息時(shí),如果是admin用戶,則返回的對(duì)象是org.springframework.security.core.userdetails.User對(duì)象
2、密碼需要加密,保存在數(shù)據(jù)庫(kù)里面的密碼也是加密方式,不允許直接保存明文(這個(gè)也是規(guī)范)
3、第三個(gè) configure 方法中,我們使用了.anyRequest().access("@UrlAuthenticationInterceptor.hasPermission(request, authentication)")交給這個(gè)方法去驗(yàn)證。驗(yàn)證的方法有很多,我們也可以這樣去寫

.anyRequest().authenticated().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {

			@Override
			public <O extends FilterSecurityInterceptor> O postProcess(O object) {
				// 權(quán)限查詢器
				// 設(shè)置你有哪些權(quán)限
				object.setSecurityMetadataSource(null);
				
				// 權(quán)限決策器
				// 判斷你有沒有權(quán)限訪問當(dāng)前的url
				object.setAccessDecisionManager(null);
				return object;
			}

		})

這里之所以沒有用.antMatchers("/XXX").hasRole(“ROLET_XXX”),是因?yàn)?,一般?xiàng)目中的權(quán)限都是動(dòng)態(tài)的,所有的資源菜單都是可配置的,在這里是無法寫死的。當(dāng)然這個(gè)要根據(jù)實(shí)際項(xiàng)目需求來做??傊渲煤莒`活,可以隨意組合。

3、驗(yàn)證碼過濾器那邊ValidateCodeFilter一定不能交給spring bean去管理,不然這個(gè)過濾器會(huì)執(zhí)行兩遍,只能直接new 出來。

AdminUserDetailsService類
    該類是用來在登錄的時(shí)候,進(jìn)行登錄校驗(yàn)的。也就是校驗(yàn)?zāi)愕馁~號(hào)密碼是否正確(其實(shí)這里只根據(jù)賬號(hào)查詢,密碼的驗(yàn)證是框架里面自帶的)。來看下這個(gè)類的實(shí)現(xiàn)

package com.hp.springboot.admin.security;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.hp.springboot.admin.convert.SysUserConvert;
import com.hp.springboot.admin.dal.ISysUserDAO;
import com.hp.springboot.admin.dal.model.SysUser;
import com.hp.springboot.admin.model.response.SysUserResponseBO;
import com.hp.springboot.database.bean.SQLBuilders;
import com.hp.springboot.database.bean.SQLWhere;

/**
 * 描述:Security需要的操作用戶的接口實(shí)現(xiàn)
 * 執(zhí)行登錄,構(gòu)建Authentication對(duì)象必須的信息
 * 如果用戶不存在,則拋出UsernameNotFoundException異常
 * 作者:黃平
 * 時(shí)間:2021年1月12日
 */
public class AdminUserDetailsService implements UserDetailsService {

	private static Logger log = LoggerFactory.getLogger(AdminUserDetailsService.class);
	
	@Autowired
	private ISysUserDAO sysUserDAO;
	
	/**
	 * 執(zhí)行登錄,構(gòu)建Authentication對(duì)象必須的信息,
	 */
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		log.info("loadUserByUsername with username={}", username);
		
		//根據(jù)登錄名,查詢用戶
		SysUser user = sysUserDAO.selectOne(SQLBuilders.create()
				.withWhere(SQLWhere.builder()
						.eq("login_name", username)
						.build()
						)
				);
		if (user == null) {
			log.warn("loadUserByUsername with user is not exists. with username={}", username);
			throw new UsernameNotFoundException("用戶不存在");
		}
		
		// 對(duì)象裝換,轉(zhuǎn)換成SysUserResponseBO對(duì)象
		SysUserResponseBO resp = SysUserConvert.dal2BOResponse(user);
		return resp;
	}

}

這個(gè)里面很簡(jiǎn)單,我們的類實(shí)現(xiàn) UserDetailsService 這個(gè)接口,并且實(shí)現(xiàn)一下loadUserByUsername這個(gè)方法。就是根據(jù)登錄名,查詢用戶的功能。

這里有必須要主要的:
我們返回值是UserDetails,所以SysUserResponseBO必須要實(shí)現(xiàn)UserDetails這個(gè)接口
在這里插入圖片描述
UserDetails里面有好幾個(gè)必須實(shí)現(xiàn)的方法,基本上看方法名就可以猜到是干什么用的,其中最重要的的一個(gè)方法

/**
	 * 獲取該用戶的角色
	 */
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return this.authorities;
	}

這個(gè)就是獲取當(dāng)前用戶所擁有的權(quán)限。這個(gè)需要根據(jù)用戶所擁有的角色去獲取。這個(gè)在上面使用 withObjectPostProcessor 這種方式校驗(yàn)的時(shí)候是必須要的,但是我這里.anyRequest().access()方法,在這里校驗(yàn),并沒有使用到這個(gè)屬性,所以這個(gè)也可以直接return null.

第二個(gè)configure方法。這里面定義了靜態(tài)資源,這個(gè)跟springMVC的靜態(tài)資源差不多。重點(diǎn)來說下第三個(gè)configure方法
    ①、如果需要,那就加上一個(gè)過濾器增加圖形驗(yàn)證碼校驗(yàn)
    ②、登錄成功后處理AdminAuthenticationSuccessHandler這個(gè)類。該類實(shí)現(xiàn)了AuthenticationSuccessHandler接口,必須實(shí)現(xiàn)一個(gè)方法,直接上代碼

@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		response.setContentType(ContentTypeConstant.APPLICATION_JSON_UTF8);
		
		// 獲取session對(duì)象
		HttpSession session = request.getSession();
		
		//設(shè)置登錄用戶session
		setUserSession(session);
		
		//查詢用戶的菜單和按鈕
		setUserMenu(session);
		
		//session中獲取當(dāng)前登錄的用戶
		SysUserResponseBO user = SecuritySessionUtil.getSessionData();
		
		// 更新最近登錄時(shí)間
		sysUserService.updateLastLoginTime(user.getId());
		
		//項(xiàng)目名稱
		session.setAttribute("projectName", projectName);
		
		// 注銷地址
		session.setAttribute("logoutUrl", AdminConstants.LOGOUT_URL);
		
		// 返回json格式數(shù)據(jù)
		Response<Object> resp = Response.success();
		try (PrintWriter out = response.getWriter()) {
			out.write(resp.toString());
			out.flush();
		}
	}

基本上看注釋也就了解每一步的意義。
我們代碼中無需寫登錄的controller,因?yàn)檫@個(gè)方法框架已經(jīng)根據(jù)你配置的loginProcessingUrl給你生成好了。這個(gè)是用戶輸入用戶名密碼后,點(diǎn)擊登錄按鈕后執(zhí)行的操作。能夠進(jìn)入這個(gè)方法,那說明用戶輸入的用戶名和密碼是正確的,后續(xù)只要保存用戶的信息,查詢用戶權(quán)限等操作。
    ③、登錄失敗處理。AdminAuthenticationFailureHandler。登錄失敗后交給這個(gè)類去處理,看下代碼:

package com.hp.springboot.admin.security.handler;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

import com.hp.springboot.admin.exception.ValidateCodeException;
import com.hp.springboot.common.bean.Response;
import com.hp.springboot.common.constant.ContentTypeConstant;

/**
 * 描述:登錄失敗處理 作者:黃平 時(shí)間:2021年1月15日
 */
public class AdminAuthenticationFailureHandler implements AuthenticationFailureHandler {

	private static Logger log = LoggerFactory.getLogger(AdminAuthenticationFailureHandler.class);

	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException exception) throws IOException, ServletException {
		log.warn("login error with exception is {}", exception.getMessage());
		response.setContentType(ContentTypeConstant.APPLICATION_JSON_UTF8);
		String message = "";
		if (exception instanceof BadCredentialsException || exception instanceof UsernameNotFoundException) {
			message = "賬戶名或者密碼輸入錯(cuò)誤!";
		} else if (exception instanceof LockedException) {
			message = "賬戶被鎖定,請(qǐng)聯(lián)系管理員!";
		} else if (exception instanceof CredentialsExpiredException) {
			message = "密碼過期,請(qǐng)聯(lián)系管理員!";
		} else if (exception instanceof AccountExpiredException) {
			message = "賬戶過期,請(qǐng)聯(lián)系管理員!";
		} else if (exception instanceof DisabledException) {
			message = "賬戶被禁用,請(qǐng)聯(lián)系管理員!";
		} else if (exception instanceof ValidateCodeException) {
			// 圖形驗(yàn)證碼輸入錯(cuò)誤
			message = exception.getMessage();
		} else if (exception instanceof InsufficientAuthenticationException) {
			message = exception.getMessage();
		} else {
			message = "登錄失敗!";
		}
		
		// 返回json格式數(shù)據(jù)
		Response<Object> resp = Response.error(message);
		try (PrintWriter out = response.getWriter()) {
			out.write(resp.toString());
			out.flush();
		}
	}

}

看代碼也基本上看出來每一步的作用。有用戶名密碼錯(cuò)誤,有用戶被禁用,有過期,鎖定等等。我這里前臺(tái)都是ajax請(qǐng)求,所以這個(gè)也是返回json格式,如果你不需要json格式,那可以按照你的要求返回指定的格式。
    ④、注銷相關(guān)。注銷接口也不需要我們?cè)赾ontroller里面寫,框架會(huì)自動(dòng)根據(jù)你的logoutUrl配置生成注銷地址。也可以自定義一個(gè)logoutSuccessHandler去在注銷后執(zhí)行。
    ⑤、權(quán)限校驗(yàn)。當(dāng)訪問一個(gè)除開第一層免過濾列表里面的url的地址時(shí),都會(huì)需要權(quán)限校驗(yàn),就都會(huì)走到UrlAuthenticationInterceptor.hasPermission(request, authentication)這個(gè)方法里面去,這個(gè)里面可以根據(jù)你的項(xiàng)目的實(shí)際邏輯去校驗(yàn)。
    ⑥、異常處理。框架里面處理異常有好多種,這里常用的accessDeniedHandler(登錄用戶訪問無權(quán)限的資源)、authenticationEntryPoint(匿名用戶訪問無權(quán)限的資源)這些都按照項(xiàng)目的實(shí)際需求去寫異常處理。
    ⑦、session管理。security框架里面對(duì)session管理非常多,可以按照鏈?zhǔn)秸{(diào)用的方式打開看看。我這里使用了invalidSessionUrl來指定session無效后跳轉(zhuǎn)到的地址,maximumSessions同一個(gè)賬號(hào)最多同時(shí)在線數(shù)。

好了,這樣一個(gè)最基本的權(quán)限控制框架就完成了。
其實(shí)我這里只使用了security的一些皮毛而且,他里面集成了非常復(fù)雜而又強(qiáng)大的功能,這個(gè)需要我們一點(diǎn)一點(diǎn)去發(fā)掘他。

總結(jié)

以上是我在項(xiàng)目中使用的一些總結(jié),完整的代碼在我的github中 我的github ,歡迎大家留言討論?。?/p>

到此這篇關(guān)于spring-security權(quán)限控制和校驗(yàn)的文章就介紹到這了,更多相關(guān)spring-security權(quán)限控制校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java接口中的代理設(shè)計(jì)模式代碼時(shí)實(shí)踐

    java接口中的代理設(shè)計(jì)模式代碼時(shí)實(shí)踐

    這篇文章主要介紹了java接口中的代理設(shè)計(jì)模式代碼時(shí)實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Java模擬微信來電提醒示例

    Java模擬微信來電提醒示例

    這篇文章主要為大家介紹了Java模擬微信來電提醒示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • java對(duì)象池管理方式common-pool2使用

    java對(duì)象池管理方式common-pool2使用

    這篇文章主要為大家介紹了java對(duì)象池common-pool2使用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • SpringBoot自定義注解及AOP的開發(fā)和使用詳解

    SpringBoot自定義注解及AOP的開發(fā)和使用詳解

    在公司項(xiàng)目中,如果需要做一些公共的功能,如日志等,最好的方式是使用自定義注解,自定義注解可以實(shí)現(xiàn)我們對(duì)想要添加日志的方法上添加,這篇文章基于日志功能來講講自定義注解應(yīng)該如何開發(fā)和使用,需要的朋友可以參考下
    2023-08-08
  • @Cacheable 拼接key的操作

    @Cacheable 拼接key的操作

    這篇文章主要介紹了@Cacheable 拼接key的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 詳解Java動(dòng)態(tài)代理的實(shí)現(xiàn)及應(yīng)用

    詳解Java動(dòng)態(tài)代理的實(shí)現(xiàn)及應(yīng)用

    這篇文章主要介紹了詳解Java動(dòng)態(tài)代理的實(shí)現(xiàn)及應(yīng)用的相關(guān)資料,希望通過本文大家能理解掌握J(rèn)ava動(dòng)態(tài)代理的使用方法,需要的朋友可以參考下
    2017-09-09
  • Java?NIO下ByteBuffer的常用方法學(xué)習(xí)

    Java?NIO下ByteBuffer的常用方法學(xué)習(xí)

    這篇文章主要帶大家來初步學(xué)習(xí)一下NIO?中的?ByteBuffer的應(yīng)用與常用方法,文中的示例代碼講解詳細(xì),對(duì)我們深入學(xué)習(xí)Java有一定的幫助,感興趣的可以了解一下
    2023-05-05
  • 淺談cookie和session(小結(jié))

    淺談cookie和session(小結(jié))

    這篇文章主要介紹了淺談cookie和session(小結(jié)),cookie和session在java web開發(fā)中扮演了十分重要的作用,本篇文章對(duì)其中的重要知識(shí)點(diǎn)做一些探究和總結(jié)
    2018-11-11
  • java實(shí)現(xiàn)中英文混合字符截取方法

    java實(shí)現(xiàn)中英文混合字符截取方法

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)中英文混合字符的截取方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • log4j升級(jí)log4j2遇到的問題及解決方式

    log4j升級(jí)log4j2遇到的問題及解決方式

    這篇文章主要介紹了log4j升級(jí)log4j2遇到的問題及解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評(píng)論