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

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

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

瀏覽:6日期: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
相關文章:
主站蜘蛛池模板: 生态板-实木生态板-生态板厂家-源木原作生态板品牌-深圳市方舟木业有限公司 | 谈股票-今日股票行情走势分析-牛股推荐排行榜 | 天津试验仪器-电液伺服万能材料试验机,恒温恒湿标准养护箱,水泥恒应力压力试验机-天津鑫高伟业科技有限公司 | 电位器_轻触开关_USB连接器_广东精密龙电子科技有限公司 | pbt头梳丝_牙刷丝_尼龙毛刷丝_PP塑料纤维合成毛丝定制厂_广州明旺 | 密集柜_档案密集柜_智能密集架_密集柜厂家_密集架价格-智英伟业 密集架-密集柜厂家-智能档案密集架-自动选层柜订做-河北风顺金属制品有限公司 | 单机除尘器 骨架-脉冲除尘器设备生产厂家-润天环保设备 | 乐泰胶水_loctite_乐泰胶_汉高乐泰授权(中国)总代理-鑫华良供应链 | 游泳池设计|设备|配件|药品|吸污机-东莞市太平洋康体设施有限公司 | 淘趣英语网 - 在线英语学习,零基础英语学习网站 | sus630/303cu不锈钢棒,440C/430F/17-4ph不锈钢研磨棒-江苏德镍金属科技有限公司 | 国际船舶网 - 船厂、船舶、造船、船舶设备、航运及海洋工程等相关行业综合信息平台 | TTCMS自助建站_网站建设_自助建站_免费网站_免费建站_天天向上旗下品牌 | 钣金加工厂家-钣金加工-佛山钣金厂-月汇好 | 不锈钢水管-不锈钢燃气管-卫生级不锈钢管件-不锈钢食品级水管-广东双兴新材料集团有限公司 | 单柱拉力机-橡胶冲片机-哑铃裁刀-江都轩宇试验机械厂 | 心肺复苏模拟人|医学模型|急救护理模型|医学教学模型上海康人医学仪器设备有限公司 | 广州食堂承包_广州团餐配送_广州堂食餐饮服务公司 - 旺记餐饮 | 单螺旋速冻机-双螺旋-流态化-隧道式-食品速冻机厂家-广州冰泉制冷 | 低压载波电能表-单相导轨式电能表-华邦电力科技股份有限公司-智能物联网综合管理平台 | 螺杆真空泵_耐腐蚀螺杆真空泵_水环真空泵_真空机组_烟台真空泵-烟台斯凯威真空 | 尾轮组_头轮组_矿用刮板_厢式刮板机_铸石刮板机厂家-双驰机械 | 太平洋亲子网_健康育儿 品质生活 | 猪I型/II型胶原-五克隆合剂-细胞冻存培养基-北京博蕾德科技发展有限公司 | 壹作文_中小学生优秀满分作文大全 | 空调风机,低噪声离心式通风机,不锈钢防爆风机,前倾皮带传动风机,后倾空调风机-山东捷风风机有限公司 | 污水处理设备维修_污水处理工程改造_机械格栅_过滤设备_气浮设备_刮吸泥机_污泥浓缩罐_污水处理设备_污水处理工程-北京龙泉新禹科技有限公司 | 正压密封性测试仪-静态发色仪-导丝头柔软性测试仪-济南恒品机电技术有限公司 | 昆明挖掘机修理厂_挖掘机翻新再制造-昆明聚力工程机械维修有限公司 | 创绿家招商加盟网-除甲醛加盟-甲醛治理加盟-室内除甲醛加盟-创绿家招商官网 | 塑胶跑道_学校塑胶跑道_塑胶球场_运动场材料厂家_中国塑胶跑道十大生产厂家_混合型塑胶跑道_透气型塑胶跑道-广东绿晨体育设施有限公司 | 搜木网 - 木业全产业链交易平台,免费搜货、低价买货! | 蜗轮丝杆升降机-螺旋升降机-丝杠升降机厂家-润驰传动 | 北京网站建设|北京网站开发|北京网站设计|高端做网站公司 | 模具ERP_模具管理系统_模具mes_模具进度管理_东莞市精纬软件有限公司 | 膜结构_ETFE膜结构_膜结构厂家_膜结构设计-深圳市烨兴智能空间技术有限公司 | 能量回馈_制动单元_电梯节能_能耗制动_深圳市合兴加能科技有限公司 | 酸度计_PH计_特斯拉计-西安云仪 纯水电导率测定仪-万用气体检测仪-低钠测定仪-米沃奇科技(北京)有限公司www.milwaukeeinst.cn | 紫外可见光分光度计-紫外分光度计-分光光度仪-屹谱仪器制造(上海)有限公司 | 武汉画册印刷厂家-企业画册印刷-画册设计印刷制作-宣传画册印刷公司 - 武汉泽雅印刷厂 | 制样机-密封锤式破碎机-粉碎机-智能马弗炉-南昌科鑫制样 |