电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

Spring Security自定義登錄原理及實現詳解

瀏覽:4日期:2023-08-15 14:42:46

1. 前言

前面的關于 Spring Security 相關的文章只是一個預熱。為了接下來更好的實戰,如果你錯過了請從 Spring Security 實戰系列 開始。安全訪問的第一步就是認證(Authentication),認證的第一步就是登錄。今天我們要通過對 Spring Security 的自定義,來設計一個可擴展,可伸縮的 form 登錄功能。

2. form 登錄的流程

下面是 form 登錄的基本流程:

Spring Security自定義登錄原理及實現詳解

只要是 form 登錄基本都能轉化為上面的流程。接下來我們看看 Spring Security 是如何處理的。

3. Spring Security 中的登錄

昨天 Spring Security 實戰干貨:自定義配置類入口WebSecurityConfigurerAdapter 中已經講到了我們通常的自定義訪問控制主要是通過 HttpSecurity 來構建的。默認它提供了三種登錄方式:

formLogin() 普通表單登錄 oauth2Login() 基于 OAuth2.0 認證/授權協議 openidLogin() 基于 OpenID 身份認證規范

以上三種方式統統是 AbstractAuthenticationFilterConfigurer 實現的,

4. HttpSecurity 中的 form 表單登錄

啟用表單登錄通過兩種方式一種是通過 HttpSecurity 的 apply(C configurer) 方法自己構造一個 AbstractAuthenticationFilterConfigurer 的實現,這種是比較高級的玩法。 另一種是我們常見的使用 HttpSecurity 的 formLogin() 方法來自定義 FormLoginConfigurer 。我們先搞一下比較常規的第二種。

4.1 FormLoginConfigurer

該類是 form 表單登錄的配置類。它提供了一些我們常用的配置方法:

loginPage(String loginPage) : 登錄 頁面而并不是接口,對于前后分離模式需要我們進行改造 默認為 /login。 loginProcessingUrl(String loginProcessingUrl) 實際表單向后臺提交用戶信息的 Action,再由過濾器UsernamePasswordAuthenticationFilter 攔截處理,該 Action 其實不會處理任何邏輯。 usernameParameter(String usernameParameter) 用來自定義用戶參數名,默認 username 。 passwordParameter(String passwordParameter) 用來自定義用戶密碼名,默認 password failureUrl(String authenticationFailureUrl) 登錄失敗后會重定向到此路徑, 一般前后分離不會使用它。 failureForwardUrl(String forwardUrl) 登錄失敗會轉發到此, 一般前后分離用到它。 可定義一個 Controller (控制器)來處理返回值,但是要注意 RequestMethod。 defaultSuccessUrl(String defaultSuccessUrl, boolean alwaysUse) 默認登陸成功后跳轉到此 ,如果 alwaysUse 為 true 只要進行認證流程而且成功,會一直跳轉到此。一般推薦默認值 false successForwardUrl(String forwardUrl) 效果等同于上面 defaultSuccessUrl 的 alwaysUse 為 true 但是要注意 RequestMethod。 successHandler(AuthenticationSuccessHandler successHandler) 自定義認證成功處理器,可替代上面所有的 success 方式 failureHandler(AuthenticationFailureHandler authenticationFailureHandler) 自定義失敗成功處理器,可替代上面所有的 success 方式 permitAll(boolean permitAll) form 表單登錄是否放開

知道了這些我們就能來搞個定制化的登錄了。

5. Spring Security 聚合登錄 實戰

接下來是我們最激動人心的實戰登錄操作。 有疑問的可認真閱讀 Spring 實戰 的一系列預熱文章。

5.1 簡單需求

我們的接口訪問都要通過認證,登陸錯誤后返回錯誤信息(json),成功后前臺可以獲取到對應數據庫用戶信息(json)(實戰中記得脫敏)。

我們定義處理成功失敗的控制器:

@RestController @RequestMapping('/login') public class LoginController { @Resource private SysUserService sysUserService; /** * 登錄失敗返回 401 以及提示信息. * * @return the rest */ @PostMapping('/failure') public Rest loginFailure() { return RestBody.failure(HttpStatus.UNAUTHORIZED.value(), '登錄失敗了,老哥'); } /** * 登錄成功后拿到個人信息. * * @return the rest */ @PostMapping('/success') public Rest loginSuccess() { // 登錄成功后用戶的認證信息 UserDetails會存在 安全上下文寄存器 SecurityContextHolder 中 User principal = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); String username = principal.getUsername(); SysUser sysUser = sysUserService.queryByUsername(username); // 脫敏 sysUser.setEncodePassword('[PROTECT]'); return RestBody.okData(sysUser,'登錄成功'); } }

然后 我們自定義配置覆寫 void configure(HttpSecurity http) 方法進行如下配置(這里需要禁用crsf):

@Configuration @ConditionalOnClass(WebSecurityConfigurerAdapter.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) public class CustomSpringBootWebSecurityConfiguration { @Configuration @Order(SecurityProperties.BASIC_AUTH_ORDER) static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { super.configure(auth); } @Override public void configure(WebSecurity web) throws Exception { super.configure(web); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .cors() .and() .authorizeRequests().anyRequest().authenticated() .and() .formLogin() .loginProcessingUrl('/process') .successForwardUrl('/login/success'). failureForwardUrl('/login/failure'); } } }

使用 Postman 或者其它工具進行 Post 方式的表單提交 http://localhost:8080/process?username=Felordcn&password=12345 會返回用戶信息:

{ 'httpStatus': 200, 'data': { 'userId': 1, 'username': 'Felordcn', 'encodePassword': '[PROTECT]', 'age': 18 }, 'msg': '登錄成功', 'identifier': '' }

把密碼修改為其它值再次請求認證失敗后 :

{ 'httpStatus': 401, 'data': null, 'msg': '登錄失敗了,老哥', 'identifier': '-9999' }

6. 多種登錄方式的簡單實現

就這么完了么?現在登錄的花樣繁多。常規的就有短信、郵箱、掃碼 ,第三方是以后我要講的不在今天范圍之內。 如何應對想法多的產品經理? 我們來搞一個可擴展各種姿勢的登錄方式。我們在上面 2. form 登錄的流程 中的 用戶 和 判定 之間增加一個適配器來適配即可。 我們知道這個所謂的 判定就是 UsernamePasswordAuthenticationFilter 。

我們只需要保證 uri 為上面配置的/process 并且能夠通過 getParameter(String name) 獲取用戶名和密碼即可 。

我突然覺得可以模仿 DelegatingPasswordEncoder 的搞法, 維護一個注冊表執行不同的處理策略。當然我們要實現一個 GenericFilterBean 在 UsernamePasswordAuthenticationFilter 之前執行。同時制定登錄的策略。

6.1 登錄方式定義

定義登錄方式枚舉 ``。

public enum LoginTypeEnum { /** * 原始登錄方式. */ FORM, /** * Json 提交. */ JSON, /** * 驗證碼. */ CAPTCHA }

6.2 定義前置處理器接口

public interface LoginPostProcessor { /** * 獲取 登錄類型 * * @return the type */ LoginTypeEnum getLoginTypeEnum(); /** * 獲取用戶名 * * @param request the request * @return the string */ String obtainUsername(ServletRequest request); /** * 獲取密碼 * * @param request the request * @return the string */ String obtainPassword(ServletRequest request); }

6.3 實現登錄前置處理過濾器

該過濾器維護了 LoginPostProcessor 映射表。 通過前端來判定登錄方式進行策略上的預處理,最終還是會交給

package cn.felord.spring.security.filter; import cn.felord.spring.security.enumation.LoginTypeEnum; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.web.filter.GenericFilterBean; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; import static org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_PASSWORD_KEY; import static org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY; /** * 預登錄控制器 * * @author Felordcn * @since 16 :21 2019/10/17 */ public class PreLoginFilter extends GenericFilterBean { private static final String LOGIN_TYPE_KEY = 'login_type'; private RequestMatcher requiresAuthenticationRequestMatcher; private Map<LoginTypeEnum, LoginPostProcessor> processors = new HashMap<>(); public PreLoginFilter(String loginProcessingUrl, Collection<LoginPostProcessor> loginPostProcessors) { Assert.notNull(loginProcessingUrl, 'loginProcessingUrl must not be null'); requiresAuthenticationRequestMatcher = new AntPathRequestMatcher(loginProcessingUrl, 'POST'); LoginPostProcessor loginPostProcessor = defaultLoginPostProcessor(); processors.put(loginPostProcessor.getLoginTypeEnum(), loginPostProcessor); if (!CollectionUtils.isEmpty(loginPostProcessors)) { loginPostProcessors.forEach(element -> processors.put(element.getLoginTypeEnum(), element)); } } private LoginTypeEnum getTypeFromReq(ServletRequest request) { String parameter = request.getParameter(LOGIN_TYPE_KEY); int i = Integer.parseInt(parameter); LoginTypeEnum[] values = LoginTypeEnum.values(); return values[i]; } /** * 默認還是Form . * * @return the login post processor */ private LoginPostProcessor defaultLoginPostProcessor() { return new LoginPostProcessor() { @Override public LoginTypeEnum getLoginTypeEnum() { return LoginTypeEnum.FORM; } @Override public String obtainUsername(ServletRequest request) { return request.getParameter(SPRING_SECURITY_FORM_USERNAME_KEY); } @Override public String obtainPassword(ServletRequest request) { return request.getParameter(SPRING_SECURITY_FORM_PASSWORD_KEY); } }; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ParameterRequestWrapper parameterRequestWrapper = new ParameterRequestWrapper((HttpServletRequest) request); if (requiresAuthenticationRequestMatcher.matches((HttpServletRequest) request)) { LoginTypeEnum typeFromReq = getTypeFromReq(request); LoginPostProcessor loginPostProcessor = processors.get(typeFromReq); String username = loginPostProcessor.obtainUsername(request); String password = loginPostProcessor.obtainPassword(request); parameterRequestWrapper.setAttribute(SPRING_SECURITY_FORM_USERNAME_KEY, username); parameterRequestWrapper.setAttribute(SPRING_SECURITY_FORM_PASSWORD_KEY, password); } chain.doFilter(parameterRequestWrapper, response); } }

6.4 驗證

通過 POST 表單提交方式 http://localhost:8080/process?username=Felordcn&password=12345&login_type=0 可以請求成功。或者以下列方式也可以提交成功:

Spring Security自定義登錄原理及實現詳解

更多的登錄方式 只需要實現接口 LoginPostProcessor 注入 PreLoginFilter

7. 總結

今天我們通過各種技術的運用實現了從簡單登錄到可動態擴展的多種方式并存的實戰運用。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持好吧啦網。

標簽: Spring
相關文章:
主站蜘蛛池模板: YT保温材料_YT无机保温砂浆_外墙保温材料_南阳银通节能建材高新技术开发有限公司 | 润东方环保空调,冷风机,厂房车间降温设备-20年深圳环保空调生产厂家 | 逗网红-抖音网红-快手网红-各大平台网红物品导航 | 校园气象站_超声波气象站_农业气象站_雨量监测站_风途科技 | 色油机-色母机-失重|称重式混料机-称重机-米重机-拌料机-[东莞同锐机械]精密计量科技制造商 | 澳威全屋定制官网|极简衣柜十大品牌|衣柜加盟代理|全屋定制招商 百度爱采购运营研究社社群-店铺托管-爱采购代运营-良言多米网络公司 | 橡胶粉碎机_橡胶磨粉机_轮胎粉碎机_轮胎磨粉机-河南鼎聚重工机械制造有限公司 | 质检报告_CE认证_FCC认证_SRRC认证_PSE认证_第三方检测机构-深圳市环测威检测技术有限公司 | 小程序开发公司-小程序制作-微信小程序开发-小程序定制-咏熠软件 | 太阳能发电系统-太阳能逆变器,控制器-河北沐天太阳能科技首页 | 泵阀展|阀门展|水泵展|流体机械展 -2025上海国际泵管阀展览会flowtech china | 常州律师事务所_常州律所_常州律师-江苏乐天律师事务所 | 连续密炼机_双转子连续密炼机_连续式密炼机-南京永睿机械制造有限公司 | 升降炉_真空气氛炉_管式电阻炉厂家-山东中辰电炉有限公司 | 地脚螺栓_材质_标准-永年县德联地脚螺栓厂家 | 门禁卡_智能IC卡_滴胶卡制作_硅胶腕带-卡立方rfid定制厂家 | 不锈钢电动球阀_气动高压闸阀_旋塞疏水调节阀_全立阀门-来自温州工业阀门巨头企业 | SOUNDWELL 编码器|电位器|旋转编码器|可调电位器|编码开关厂家-广东升威电子制品有限公司 | 珠海网站建设_响应网站建设_珠海建站公司_珠海网站设计与制作_珠海网讯互联 | 帽子厂家_帽子工厂_帽子定做_义乌帽厂_帽厂_制帽厂_帽子厂_浙江高普制帽厂 | 南京租车,南京汽车租赁,南京包车,南京会议租车-南京七熹租车 | 河南mpp电力管_mpp电力管生产厂家_mpp电力电缆保护管价格 - 河南晨翀实业 | 鹤壁创新仪器公司-全自动量热仪,定硫仪,煤炭测硫仪,灰熔点测定仪,快速自动测氢仪,工业分析仪,煤质化验仪器 | 成都办公室装修-办公室设计-写字楼装修设计-厂房装修-四川和信建筑装饰工程有限公司 | 北京发电机出租_发电机租赁_北京发电机维修 - 河北腾伦发电机出租 | 成都离婚律师|成都结婚律师|成都离婚财产分割律师|成都律师-成都离婚律师网 | 湖南专升本-湖南省专升本报名-湖南统招专升本考试网 | 玻璃钢型材-玻璃钢风管-玻璃钢管道,生产厂家-[江苏欧升玻璃钢制造有限公司] | 扫地车厂家-山西洗地机-太原电动扫地车「大同朔州吕梁晋中忻州长治晋城洗地机」山西锦力环保科技有限公司 | 西安烟道厂家_排气道厂家_包立管厂家「陕西西安」推荐西安天宇烟道 | 烟气在线监测系统_烟气在线监测仪_扬尘检测仪_空气质量监测站「山东风途物联网」 | 高压贴片电容|贴片安规电容|三端滤波器|风华电容代理南京南山 | 加热制冷恒温循环器-加热制冷循环油浴-杭州庚雨仪器有限公司 | 真空包装机-诸城市坤泰食品机械有限公司 | 沉降天平_沉降粒度仪_液体比重仪-上海方瑞仪器有限公司 | 郑州律师咨询-郑州律师事务所_河南锦盾律师事务所 | 微量水分测定仪_厂家_卡尔费休微量水分测定仪-淄博库仑 | 翅片管散热器价格_钢制暖气片报价_钢制板式散热器厂家「河北冀春暖气片有限公司」 | 青州搬家公司电话_青州搬家公司哪家好「鸿喜」青州搬家 | 京马网,京马建站,网站定制,营销型网站建设,东莞建站,东莞网站建设-首页-京马网 | 螺纹三通快插接头-弯通快插接头-宁波舜驰气动科技有限公司 |