AuthenticationProvider

  • 默认实现:DaoAuthenticationProvider

授权方式提供者,判断授权有效性,用户有效性,在判断用户是否有效性,它依赖于UserDetailsService实例,开发人员可以自定义UserDetailsService的实现。

  1. additionalAuthenticationChecks方法校验密码有效性
  2. retrieveUser方法根据用户名获取用户
  3. createSuccessAuthentication完成授权持久化
@Component
@Slf4j
public class LindAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @Autowired
UserDetailsService userDetailsService; @Autowired
private PasswordEncoder passwordEncoder; /**
* 校验密码有效性.
*
* @param userDetails .
* @param authentication .
* @throws AuthenticationException .
*/
@Override
protected void additionalAuthenticationChecks(
UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
} String presentedPassword = authentication.getCredentials().toString(); if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value"); throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
} /**
* 获取用户.
*
* @param username .
* @param authentication .
* @return
* @throws AuthenticationException .
*/
@Override
protected UserDetails retrieveUser(
String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
UserDetails loadedUser = userDetailsService.loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
}
/**
* 授权持久化.
*/
@Override
protected Authentication createSuccessAuthentication(Object principal,
Authentication authentication, UserDetails user) {
return super.createSuccessAuthentication(principal, authentication, user);
}

AuthenticationFilter

  • 默认实现:UsernamePasswordAuthenticationFilter

授权过滤器,你可以自定义它,并把它添加到默认过滤器前或者后去执行,主要用来到授权的持久化,它可以从请求上下文中获取你的user,password等信息,然后去判断它是否符合规则,最后通过authenticate方法去授权。默认的UsernamePasswordAuthenticationFilter过滤器,主要判断请求方式是否为post,并且对username和password进行了默认值的处理,总之,在这个过滤器里不会涉及到具体业务。

public class LindUserNameAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

  public LindUserNameAuthenticationFilter() {
super(new AntPathRequestMatcher("/login", "GET"));
} @Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String username = request.getParameter("username");
String password = request.getParameter("password"); if (username == null) {
throw new InternalAuthenticationServiceException("Failed to get the username");
} if (password == null) {
throw new InternalAuthenticationServiceException("Failed to get the password");
} UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
return this.getAuthenticationManager().authenticate(authRequest);
}
}

UserDetialsService

这是一个接口,有默认的实现方式,一般的,我们需要根据业务去重新实现它,比如从你的用户表获取当前授权的用户信息,你需要在UserDetialsService实现类里对用户表进行读取操作;它一般会在AuthenticationProvider里的retrieveUser方法中被使用,这就像面向对象里的模板方法模式一样,springSecurity把检验的步骤设计好了,咱们开发只要根据规则去实现具体细节就好。

@Component
public class MyUserDetailService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder; @Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
/*
设置用户和角色需要注意:
1. commaSeparatedStringToAuthorityList放入角色时需要加前缀ROLE_,而在controller使用时不需要加ROLE_前缀
2. 放入的是权限时,不能加ROLE_前缀,hasAuthority与放入的权限名称对应即可
*/
List<UserDetails> userDetailsList = new ArrayList<>();
userDetailsList.add(User.builder()
.username("admin")
.password(passwordEncoder.encode("123"))
.authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("read,ROLE_ADMIN")).build());
userDetailsList.add(User.builder()
.username("user")
.password(passwordEncoder.encode("123"))
.authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("read,ROLE_USER"))
.build()); //获取用户
return userDetailsList.stream()
.filter(o -> o.getUsername().equals(name))
.findFirst()
.orElse(null); }
}

在WebSecurityConfig里开启它

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
LindAuthenticationSuccessHandler lindAuthenticationSuccessHandler; @Autowired
LindAuthenticationFailHandler lindAuthenticationFailHandler;
@Autowired
LindAuthenticationProvider lindAuthenticationProvider; @Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/index").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")//按路由授权
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/hello")//默认登录成功后跳转的页面
.successHandler(lindAuthenticationSuccessHandler)
.failureHandler(lindAuthenticationFailHandler)
.permitAll()
.and()
.addFilterAt(lindAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class).authorizeRequests().and()
.logout()
.permitAll();
} /**
* 自定义的Filter.
*/
@Bean
LindUserNameAuthenticationFilter lindAuthenticationFilter() {
LindUserNameAuthenticationFilter phoneAuthenticationFilter = new LindUserNameAuthenticationFilter();
ProviderManager providerManager =
new ProviderManager(Collections.singletonList(lindAuthenticationProvider));
phoneAuthenticationFilter.setAuthenticationManager(providerManager);
phoneAuthenticationFilter.setAuthenticationSuccessHandler(lindAuthenticationSuccessHandler);
phoneAuthenticationFilter.setAuthenticationFailureHandler(lindAuthenticationFailHandler);
return phoneAuthenticationFilter;
} /**
* 密码生成策略.
*
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

认证时执行的顺序

  1. LindUserNameAuthenticationFilter
  2. LindAuthenticationProvider.retrieveUser
  3. LindAuthenticationProvider.additionalAuthenticationChecks
  4. UserDetailsService
  5. Authentication

springSecurity源码:https://github.com/spring-projects/spring-security

SpringSecurity自定义AuthenticationProvider和AuthenticationFilter的更多相关文章

  1. SpringSecurity 自定义用户 角色 资源权限控制

    SpringSecurity 自定义用户 角色 资源权限控制 package com.joyen.learning.security; import java.sql.ResultSet; impor ...

  2. SpringSecurity 自定义表单登录

    SpringSecurity 自定义表单登录 本篇主要讲解 在SpringSecurity中 如何 自定义表单登录 , SpringSecurity默认提供了一个表单登录,但是实际项目里肯定无法使用的 ...

  3. SpringSecurity自定义登陆页面和跳转页面

    如果我们不用form-login说明登陆界面,springsecurity框架将自动为我们生成登陆界面 现在我们不想用自动生成的登陆界面了,而想使用自定义的漂亮的登陆界面 则需要使用<secur ...

  4. springSecurity自定义认证配置

    上一篇讲了springSecurity的简单入门的小demo,认证用户是在xml中写死的.今天来说一下自定义认证,读取数据库来实现认证.当然,也是非常简单的,因为仅仅是读取数据库,权限是写死的,因为相 ...

  5. SpringSecurity自定义过滤器

    applicationContext-security.xml: <beans:beans xmlns="http://www.springframework.org/schema/s ...

  6. Spring-Security 自定义Filter完成验证码校验

    Spring-Security的功能主要是由一堆Filter构成过滤器链来实现,每个Filter都会完成自己的一部分工作.我今天要做的是对UsernamePasswordAuthenticationF ...

  7. SpringSecurity自定义UsernamePasswordAuthenticationFilter

    UsernamePasswordAuthenticationFilter介绍 UsernamePasswordAuthenticationFilter是AbstractAuthenticationPr ...

  8. SpringSecurity自定义注解和处理器

    登录功能 添加一个配置类 @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Reso ...

  9. Spring-Security自定义登录页&inMemoryAuthentication验证

    Spring Security是为基于Spring的应用程序提供声明式安全保护的安全性框架.框架下内容比较多,可以做到按照角色权限对请求路径进行限制.今天主要验证自定义登录页,在内存用户存储中进行请求 ...

随机推荐

  1. 模板——无旋Treap

    #include "bits/stdc++.h" using namespace std; inline int read(){ ,k=;char ch=getchar(); :, ...

  2. 【Richard 的刷(水)题记录】

    大概想了想,还是有个记录比较好. 9/24 网络流一日游: 最大流:bzoj1711[Usaco2007 Open]Dining 拆点 BZOJ 3993 Sdoi2015 星际战争 二分 P.S.这 ...

  3. 一个Java程序员的2018年展望与2017年总结

    回顾2017年,可以说是对我而言有重大转折的一年.我们选择放弃了北京,来到了杭州,开始了新的生活.房子的事情也基本上落实了,虽然其中经历了种种坎坷,但是结局还是美好的,现在在等贷款放贷.中国人嘛,没有 ...

  4. BZOJ_1031_[JSOI2007]字符加密Cipher_后缀数组

    BZOJ_1031_[JSOI2007]字符加密Cipher_后缀数组 Description 喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法 :把 ...

  5. 手游热更新方案--Unity3D下的CsToLua技术

    WeTest 导读 CsToLua工具将客户端 C#源码自动转换为Lua,实现热更新,本文以麻将项目为例介绍客户端技术细节. 麻将项目架构 其中ChinaMahjong-CSLua为C#工程,实现麻将 ...

  6. 使用jquery 的ajax 与 Java servlet的交互

    由于是使用jquery的 所以别忘记导入jq 下面是jsp文件 <%@ page language="java" contentType="text/html; c ...

  7. java happens-before原则规则

    程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作: 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作: volatile变量规则:对一个变量的写操 ...

  8. springboot mybatis 多数据源配置

    首先导入mybatis等包,这里就不多说. 下面是配置多数据源和mybatis,每个数据源对应一套mybatis模板 数据源1: package com.aaaaaaa.config.datasour ...

  9. 从壹开始前后端分离【 .NETCore2.1 +Vue 2 +AOP+DI】框架之一 || 前言

    缘起 作为一个.Net攻城狮已经4年有余了,一直不温不火,正好近来项目不是很忙,闲得无聊,搞一搞新技术,一方面是打发无聊的时间,一方面也是督促自己该学习辣!身边的大神都转行的转行,加薪的加薪,本人比较 ...

  10. Shell学习心得(一):变量

     1.begin #!/bin/bash echo "Hello World !" #! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell. ec ...