参考连接 自定义认证逻辑的两种方式(高级玩法)
我的需求是需要在传多个参数,从数据库中查询
自定义UsernamePasswordAuthenticationFilter
/**
* @author Junisyoan
* @date 2021年2月23日
* 验证登录用户密码
*/
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
...//省略
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)
|| request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)
) {
ObjectMapper mapper = new ObjectMapper();
UsernamePasswordAuthenticationToken authRequest;
try {
InputStream is = request.getInputStream();
@SuppressWarnings("unchecked")
Map<String, String> authenticationBean = mapper.readValue(is, Map.class);
String username = authenticationBean.get("username");
String password = authenticationBean.get("password").trim();
//额外参数
String enterpriseCode = authenticationBean.get("enterpriseCode");
authRequest = new CustomUsernamePasswordAuthenticationToken(username,password,enterpriseCode);
super.setDetails(request, authRequest);
} catch (IOException e) {
e.printStackTrace();
authRequest = new UsernamePasswordAuthenticationToken("", "");
}
return authenticationManager.authenticate(authRequest);
} else {
return super.attemptAuthentication(request, response);
}
}
...//省略
}
自定义 UsernamePasswordAuthenticationToken
/**
* @author shangchain Junisyoan
* 2021/8/9
* 自定义认证token
*/
public class CustomUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken {
/**
* 企业编码
*/
private final String enterpriseCode;
public CustomUsernamePasswordAuthenticationToken(Object principal, Object credentials, String enterpriseCode) {
super(principal, credentials);
this.enterpriseCode = enterpriseCode;
}
public String getEnterpriseCode() {
return enterpriseCode;
}
}
自定义AbstractUserDetailsAuthenticationProvider这里主要是重写retrieveUser方法,从数据库中查数据,其他的从DaoAuthenticationProvider抄的
/**
* @author Junisyoan
* 2021/8/9
* 客户端自定义登录验证
*/
public class ClientLoginAuthProvider extends AbstractUserDetailsAuthenticationProvider {
...//省略代码
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
CustomUsernamePasswordAuthenticationToken auth = (CustomUsernamePasswordAuthenticationToken) authentication;
//多个参数
UserDetails loadedUser = userDetailsService.loadUserByUsername(username,auth.getEnterpriseCode());
if (loadedUser == null) {
throw new InternalAuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
...//省略代码
}
最后覆盖原有的provider
/**
* @author Junisyoan
*
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//..
@Bean
public ClientLoginAuthProvider provider(){
ClientLoginAuthProvider provider = new ClientLoginAuthProvider(userService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() {
return new ProviderManager(Collections.singletonList(provider()));
}
//...
}
运行结果
2021-08-09 18:16:37 JRebel: Reloading SQL maps
c.s.s.a.filter.JwtAuthenticationFilter : 认证令牌 ===> null
c.s.s.s.s.impl.ClientUserServiceImpl : 开始认证用户:admin
这里只会有一次认证,多次认证就是SecurityConfig配置错了