spring security使用分类:
如何使用spring security,相信百度过的都知道,总共有四种用法,从简到深为:
1、不用数据库,全部数据写在配置文件,这个也是官方文档里面的demo;
2、使用数据库,根据spring security默认实现代码设计数据库,也就是说数据库已经固定了,这种方法不灵活,而且那个数据库设计得很简陋,实用性差;
3、spring security和Acegi不同,它不能修改默认filter了,但支持插入filter,所以根据这个,我们可以插入自己的filter来灵活使用;
4、暴力手段,修改源码,前面说的修改默认filter只是修改配置文件以替换filter而已,这种是直接改了里面的源码,但是这种不符合OO设计原则,而且不实际,不可用。
本文主要介绍了关于spring security自定义认证登录的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。
1.概要
1.1.简介
spring security是一种基于 Spring AOP 和 Servlet 过滤器的安全框架,以此来管理权限认证等。
1.2.spring security 自定义认证流程
1)认证过程
生成未认证的AuthenticationToken
↑(获取信息) (根据AuthenticationToken分配provider) AuthenticationFilter -> AuthenticationManager -> AuthenticationProvider ↓(认证) UserDetails(一般查询数据库获取) ↓(通过) 生成认证成功的AuthenticationToken ↓(存放) SecurityContextHolder
2)将AuthenticationFilter加入到security过滤链(资源服务器中配置),如:
http.addFilterBefore(AuthenticationFilter, AbstractPreAuthenticatedProcessingFilter.class)
或者:
http.addFilterAfter(AuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
2.以手机号短信登录为例
2.1.开发环境
2.2.核心代码分析
2.2.1.自定义登录认证流程
2.2.1.1.自定义认证登录Token
/** * 手机登录Token * * @author : CatalpaFlat */ public class MobileLoginAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationToken.class.getName()); private final Object principal; public MobileLoginAuthenticationToken(String mobile) { super(null); this.principal = mobile; this.setAuthenticated(false); logger.info("MobileLoginAuthenticationToken setAuthenticated ->false loading ..."); } public MobileLoginAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; // must use super, as we override super.setAuthenticated(true); logger.info("MobileLoginAuthenticationToken setAuthenticated ->true loading ..."); } @Override public void setAuthenticated(boolean authenticated) { if (authenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return this.principal; } @Override public void eraseCredentials() { super.eraseCredentials(); } }
注:
setAuthenticated():判断是否已认证
2.2.1.1.自定义认证登录过滤器
/** * 手机短信登录过滤器 * * @author : CatalpaFlat */ public class MobileLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private boolean postOnly = true; private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationFilter.class.getName()); @Getter @Setter private String mobileParameterName; public MobileLoginAuthenticationFilter(String mobileLoginUrl, String mobileParameterName, String httpMethod) { super(new AntPathRequestMatcher(mobileLoginUrl, httpMethod)); this.mobileParameterName = mobileParameterName; logger.info("MobileLoginAuthenticationFilter loading ..."); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } //get mobile String mobile = obtainMobile(request); //assemble token MobileLoginAuthenticationToken authRequest = new MobileLoginAuthenticationToken(mobile); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } /** * 设置身份认证的详情信息 */ private void setDetails(HttpServletRequest request, MobileLoginAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } /** * 获取手机号 */ private String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameterName); } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } }
注:attemptAuthentication()方法:
2.2.1.1.自定义认证登录提供者
/** * 手机短信登录认证提供者 * * @author : CatalpaFlat */ public class MobileLoginAuthenticationProvider implements AuthenticationProvider { private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationProvider.class.getName()); @Getter @Setter private UserDetailsService customUserDetailsService; public MobileLoginAuthenticationProvider() { logger.info("MobileLoginAuthenticationProvider loading ..."); } /** * 认证 */ @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { //获取过滤器封装的token信息 MobileLoginAuthenticationToken authenticationToken = (MobileLoginAuthenticationToken) authentication; //获取用户信息(数据库认证) UserDetails userDetails = customUserDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); //不通过 if (userDetails == null) { throw new InternalAuthenticationServiceException("Unable to obtain user information"); } //通过 MobileLoginAuthenticationToken authenticationResult = new MobileLoginAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } /** * 根据token类型,来判断使用哪个Provider */ @Override public boolean supports(Class<?> authentication) { return MobileLoginAuthenticationToken.class.isAssignableFrom(authentication); } }
注:authenticate()方法
2.2.1.1.自定义认证登录认证配置
@Configuration(SpringBeanNameConstant.DEFAULT_CUSTOM_MOBILE_LOGIN_AUTHENTICATION_SECURITY_CONFIG_BN) public class MobileLoginAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationSecurityConfig.class.getName()); @Value("${login.mobile.url}") private String defaultMobileLoginUrl; @Value("${login.mobile.parameter}") private String defaultMobileLoginParameter; @Value("${login.mobile.httpMethod}") private String defaultMobileLoginHttpMethod; @Autowired private CustomYmlConfig customYmlConfig; @Autowired private UserDetailsService customUserDetailsService; @Autowired private AuthenticationSuccessHandler customAuthenticationSuccessHandler; @Autowired private AuthenticationFailureHandler customAuthenticationFailureHandler; public MobileLoginAuthenticationSecurityConfig() { logger.info("MobileLoginAuthenticationSecurityConfig loading ..."); } @Override public void configure(HttpSecurity http) throws Exception { MobilePOJO mobile = customYmlConfig.getLogins().getMobile(); String url = mobile.getUrl(); String parameter = mobile.getParameter().getMobile(); String httpMethod = mobile.getHttpMethod(); MobileLoginAuthenticationFilter mobileLoginAuthenticationFilter = new MobileLoginAuthenticationFilter(StringUtils.isBlank(url) ? defaultMobileLoginUrl : url, StringUtils.isBlank(parameter) ? defaultMobileLoginUrl : parameter, StringUtils.isBlank(httpMethod) ? defaultMobileLoginHttpMethod : httpMethod); mobileLoginAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); mobileLoginAuthenticationFilter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler); mobileLoginAuthenticationFilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler); MobileLoginAuthenticationProvider mobileLoginAuthenticationProvider = new MobileLoginAuthenticationProvider(); mobileLoginAuthenticationProvider.setCustomUserDetailsService(customUserDetailsService); http.authenticationProvider(mobileLoginAuthenticationProvider) .addFilterAfter(mobileLoginAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } }
注:configure()方法
实例化AuthenticationFilter和AuthenticationProvider
将AuthenticationFilter和AuthenticationProvider添加到spring security中。
2.2.2.基于redis自定义验证码校验
2.2.2.1.基于redis自定义验证码过滤器
/** * 验证码过滤器 * * @author : CatalpaFlat */ @Component(SpringBeanNameConstant.DEFAULT_VALIDATE_CODE_FILTER_BN) public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(ValidateCodeFilter.class.getName()); @Autowired private CustomYmlConfig customYmlConfig; @Autowired private RedisTemplate<Object, Object> redisTemplate; /** * 验证请求url与配置的url是否匹配的工具类 */ private AntPathMatcher pathMatcher = new AntPathMatcher(); public ValidateCodeFilter() { logger.info("Loading ValidateCodeFilter..."); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String url = customYmlConfig.getLogins().getMobile().getUrl(); if (pathMatcher.match(url, request.getRequestURI())) { String deviceId = request.getHeader("deviceId"); if (StringUtils.isBlank(deviceId)) { throw new CustomException(HttpStatus.NOT_ACCEPTABLE.value(), "Not deviceId in the head of the request"); } String codeParamName = customYmlConfig.getLogins().getMobile().getParameter().getCode(); String code = request.getParameter(codeParamName); if (StringUtils.isBlank(code)) { throw new CustomException(HttpStatus.NOT_ACCEPTABLE.value(), "Not code in the parameters of the request"); } String key = SystemConstant.DEFAULT_MOBILE_KEY_PIX + deviceId; SmsCodePO smsCodePo = (SmsCodePO) redisTemplate.opsForValue().get(key); if (smsCodePo.isExpried()){ throw new CustomException(HttpStatus.BAD_REQUEST.value(), "The verification code has expired"); } String smsCode = smsCodePo.getCode(); if (StringUtils.isBlank(smsCode)) { throw new CustomException(HttpStatus.BAD_REQUEST.value(), "Verification code does not exist"); } if (StringUtils.equals(code, smsCode)) { redisTemplate.delete(key); //let it go filterChain.doFilter(request, response); } else { throw new CustomException(HttpStatus.BAD_REQUEST.value(), "Validation code is incorrect"); } }else { //let it go filterChain.doFilter(request, response); } } }
注:doFilterInternal()
自定义验证码过滤校验
2.2.2.2.将自定义验证码过滤器添加到spring security过滤器链
http.addFilterBefore(validateCodeFilter, AbstractPreAuthenticatedProcessingFilter.class)
注:添加到认证预处理过滤器前
3.测试效果
最后附上源码地址:https://gitee.com/CatalpaFlat/springSecurity.git (本地下载)
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对小牛知识库的支持。
问题内容: 这是我的情况: 一个Web应用程序对许多应用程序执行某种SSO 登录的用户,而不是单击链接,该应用就会向正确的应用发布包含用户信息(名称,pwd [无用],角色)的帖子 我正在其中一个应用程序上实现SpringSecurity以从其功能中受益(会话中的权限,其类提供的方法等) 因此,我需要开发一个 自定义过滤器 -我猜想-能够从请求中检索用户信息,通过自定义 DetailsUserSe
springsecurity oauth2.0 谁做过记录登录日志?监听事件好像没法区分是什么原因失败的、比如client错误还是用户名错误
本文向大家介绍解析SpringSecurity自定义登录验证成功与失败的结果处理问题,包括了解析SpringSecurity自定义登录验证成功与失败的结果处理问题的使用技巧和注意事项,需要的朋友参考一下 一、需要自定义登录结果的场景 在我之前的文章中,做过登录验证流程的源码解析。其中比较重要的就是 当我们登录成功的时候,是由AuthenticationSuccessHandler进行登录结果处理,
Django 自带的认证系统足够应付大多数情况,但你或许不打算使用现成的认证系统。定制自己的项目的权限系统需要了解哪些一些关键点,即Django中哪些部分是能够扩展或替换的。这个文档提供了如何定制权限系统的细节。 “认证”后端 在以下情形时可被扩展:当一个 User 模型对象带有用户名和密码时,且需要有别于 Django 默认的认证功能。 你可为你的模型提供可通过 Django 权限系统检查的 定
我们希望使用外部身份提供者将现有的Spring Security项目从自定义用户名/密码实现(UserDetailsService等)迁移到oauth2登录。 但是,当通过外部提供程序登录时,安全上下文中的身份验证对象是一个,主体是一个。 由于我们在应用程序中使用的都是自定义身份验证主体,因此我们希望将转换为自定义对象。 对于oauth2资源服务器,似乎有一个API可让您将JWtAuthentia
本文向大家介绍SpringSecurity 默认表单登录页展示流程源码,包括了SpringSecurity 默认表单登录页展示流程源码的使用技巧和注意事项,需要的朋友参考一下 SpringSecurity 默认表单登录页展示流程源码 本篇主要讲解 SpringSecurity提供的默认表单登录页 它是如何展示的的流程, 涉及 1.FilterSecurityInterceptor, 2.Excep