spring security使用数据库验证的逻辑处理
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
authenticationProvider.setPasswordEncoder(passwordEncoder());
auth.authenticationProvider(authenticationProvider);
//auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Autowired
@Qualifier("userDetailsService")
@Override
public void setUserDetailsService(UserDetailsService userDetailsService) {
super.setUserDetailsService(userDetailsService);
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try {
//调用上层验证逻辑
Authentication auth = super.authenticate(authentication);
//如果验证通过登录成功则重置尝试次数, 否则抛出异常
userDetailsDao.resetFailAttempts(authentication.getName());
return auth;
} catch (BadCredentialsException e) {
//如果验证不通过,则更新尝试次数,当超过次数以后抛出账号锁定异常
userDetailsDao.updateFailAttempts(authentication.getName());
throw e;
} catch (LockedException e){
//该用户已经被锁定,则进入这个异常
String error;
UserAttempts userAttempts =
userDetailsDao.getUserAttempts(authentication.getName());
if(userAttempts != null){
Date lastAttempts = userAttempts.getLastModified();
error = "用户已经被锁定,用户名 : "
+ authentication.getName() + "最后尝试登陆时间 : " + lastAttempts;
}else{
error = e.getMessage();
}
throw new LockedException(error);
}
}
Authentication authenticate(Authentication authentication) throws AuthenticationException;
实现方法中首先获取security定义的接口UserDetails,先从缓存userCache中获取,如果不存在,则调用方法retrieveUser。
UserDetails loadedUser;
try {
loadedUser = this.getUserDetailsService().loadUserByUsername(username);
}
catch (UsernameNotFoundException notFound) {
if (authentication.getCredentials() != null) {
String presentedPassword = authentication.getCredentials().toString();
passwordEncoder.isPasswordValid(userNotFoundEncodedPassword,
presentedPassword, null);
}
throw notFound;
}
.....
此处调用的是自定义的UserDetailsService中loadUserByUsername方法。于是可以看出自定义的UserDetailsService实现类关键是实现loadUserByUsername方法。
@Override
protected List<UserDetails> loadUsersByUsername(String username) {
return getJdbcTemplate().query(super.getUsersByUsernameQuery(), new Object[]{username},
(rs, rowNum) -> {
String username1 = rs.getString("username");
String password = rs.getString("password");
boolean enabled = rs.getBoolean("enabled");
boolean accountNonExpired = rs.getBoolean("accountNonExpired");
boolean credentialsNonExpired = rs.getBoolean("credentialsNonExpired");
boolean accountNonLocked = rs.getBoolean("accountNonLocked");
return new User(username1, password, enabled, accountNonExpired, credentialsNonExpired,
accountNonLocked, AuthorityUtils.NO_AUTHORITIES);
});
}
@Override
protected UserDetails createUserDetails(String username, UserDetails userFromUserQuery, List<GrantedAuthority> combinedAuthorities) {
String returnUsername = userFromUserQuery.getUsername();
if (!super.isUsernameBasedPrimaryKey()) {
returnUsername = username;
}
return new User(returnUsername, userFromUserQuery.getPassword(),
userFromUserQuery.isEnabled(),
userFromUserQuery.isAccountNonExpired(),
userFromUserQuery.isCredentialsNonExpired(),
userFromUserQuery.isAccountNonLocked(), combinedAuthorities);
}
在这里我们根据需要指定各个值,例如用户名,密码,是否可用,账号和密码是否过期,是否账号被锁等,所以如果已经设计完成的数据表中字段名称不一致也没有关系,只要含义相同,获取值指定即可。
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findByUserName(username);
if (user == null) {
throw new UsernameNotFoundException("该用户不存在:" + username);
}
List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRole());
return buildUserForAuthentication(user, authorities);
}
// 把自定义的User转换成org.springframework.security.core.userdetails.User
private org.springframework.security.core.userdetails.User buildUserForAuthentication(
User user,
List<GrantedAuthority> authorities) {
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<>();
// Build user's authorities
for (UserRole userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
return new ArrayList<>(setAuths);
}
在方法中使用hibernate的方式获取自定义的User实例,然后转换成security中的org.springframework.security.core.userdetails.User即可,org.springframework.security.core.userdetails.User是接口UserDetails的实现类。
spring security使用数据库验证的逻辑处理的更多相关文章
- spring security结合数据库验证用户-XML配置方式
之前的用户信息我们都是使用的内存用户,测试例子可以,实际中使用肯定不行,需要结合数据库进行验证用户.这就是本节的重点: 项目目录如下: 在之前的项目中的依赖中添加两个依赖: <dependen ...
- spring security结合数据库验证用户-注解方式
项目目录结构如下: 首先数据库的建立和数据导入,以及一些类的依赖参考XML配置方式,需要修改一些配置. 一.在AppConfig文件中添加DataSource的配置 @Bean(name = &quo ...
- spring security关闭http验证 和 springboot 使用h2数据库
spring security关闭http验证 最近在跑demo的过程中,访问swagger页面的时候需要验证登录,记得在之前写的代码中是关闭了security验证,无需登录成功访问,直接在appli ...
- Spring Security 概念基础 验证流程
Spring Security 概念基础 验证流程 认证&授权 认证:确定是否为合法用户 授权:分配角色权限(分配角色,分配资源) 认证管理器(Authentication Manager) ...
- 自定义Spring Security的身份验证失败处理
1.概述 在本快速教程中,我们将演示如何在Spring Boot应用程序中自定义Spring Security的身份验证失败处理.目标是使用表单登录方法对用户进行身份验证. 2.认证和授权(Authe ...
- spring boot系列--spring security (基于数据库)登录和权限控制
先说一下AuthConfig.java Spring Security的主要配置文件之一 AuthConfig 1 @Configuration 2 @EnableWebSecurity 3 publ ...
- Spring Security在登录验证中增加额外数据(如验证码)
在使用Spring Security框架过程中,经常会有这样的需求,即在登录验证时,附带增加额外的数据,如验证码.用户类型等.下面将介绍如何实现. 注:我的工程是在Spring Boot框架基础上的, ...
- Spring Security使用数据库数据完成认证--练气后期2
写在前面 没错,这篇文章还是练气后期!但作者我相信筑基指日可待! 在前一篇文章当中,我们简单地分析了一下Spring Security的认证流程,知道了如果想要实现对自己用户数据(账户.角色.权限)的 ...
- spring security使用数据库资源
国内对权限系统的基本要求是将用户权限和被保护资源都放在数据库里进行管理,在这点上Spring Security并没有给出官方的解决方案,为此我们需要对Spring Security进行扩展.. 数据库 ...
随机推荐
- boost::interprocess(2)
//doc_anonymous_mutex_shared_data.hpp #include <boost/interprocess/sync/interprocess_mutex.hpp> ...
- label 两次点击 事件冒泡 使用时间戳的解决方案
情况描述:在页面中input 和 label 通过for banding 然后点击input 或者label的时候都要执行一个方法 但是在点击label的时候有两次执行两次的情况,及监听到的cli ...
- 160708、JQuery解析XML数据的demo
用JavaScript解析XML数据是常见的编程任务,JavaScript能做的,JQuery当然也能做.下面我们来总结几个使用JQuery解析XML的例子. 方案1 当后台返回的数据类型是xml对象 ...
- mysql insert中用case
insert into urls(company,counterType,mdUrl,tradeUrl) values('test', CASE 'test'WHEN 'CTP' THEN 1WHEN ...
- 转!java web项目 build path 导入jar包,tomcat启动报错 找不到该类
在eclipse集成tomcat开发java web项目时,引入的外部jar包,编译通过,但启动tomcat运行web时提示找不到jar包内的类,需要作如下配置,将jar包在部署到集成的tomcat环 ...
- django之多表查询-2
2018-11-14 一 \\ 基于双下划线的跨表查询: 套路一样,用__跨表 -一对多 -多对多 from app.models import * 查询出版社为北京出版社出版的所有图书的名字,价格 ...
- 【我的Android进阶之旅】Realm数据库学习资料汇总(持续更新)
介绍 realm是一个跨平台移动数据库引擎,支持iOS.OS X(Objective-C和Swift)以及Android. 2014年7月发布.由YCombinator孵化的创业团队历时几年打造,是第 ...
- xxxservlet继承HttpServlet类
"HttpServlet类被定义为抽象类,但是源码里面没有抽象方法.所以没有一定要求实现的方法.之所以定义为抽象类,是因为他继承了GenericServlet这个抽象类.并没有全部实现里面的 ...
- Linux学习笔记(12)linux文件目录与用户管理
基本常用目录 1.文件及目录 1.1.文件/文件夹权限 用法: (1) chgrp group_name dir_name/file_name, (2) chown user_name:g ...
- eslasticsearch操作集锦
索引-index:一个索引就是一个拥有几分相似特征的文档的集合.比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引.一个索引由一个名字来标识(必须全部是小写字母的),并且 ...