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进行扩展.. 数据库 ...
随机推荐
- Asp.Net WebApi核心对象解析
在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...
- IntelliJ中的main函数和System.out.println()快捷输入方式
转自:https://blog.csdn.net/assassinsshadow/article/details/73557375 main快捷输入 psvm System.out.println() ...
- angularJS中的ng-show、ng-if指令
angularJS中的ng-show.ng-hide.ng-if指令都可以用来控制dom元素的显示或隐藏. 1. ng-show和ng-hide 根据所给表达式的值来显示或隐藏HTML元素.元素会渲染 ...
- git base commond
打开Git Bash 命令:先写 git status, 它会告诉你怎么做 1. git pull (把git库中代码拉下来) 2. $ git status (查看状态) 3. $ gi ...
- 第二课——解析mysqldump命令和mysqlbinlog命令+innodb和Myisam存储引擎简介
环境说明 mysql版本:Percona-Server-5.6.30 IP:10.7.15.167 端口:3306 安装目录:/httx/run/mysql 数据目录:/httx/run/mysql/ ...
- easyui的datagrid无数据时下方滚动条不显示的解决办法(标题栏显示不完全)
easyui在写datagrid的时候标题栏有时候因为太多.太长所以无法显示所有的列,而且没数据的时候下方的滚动条是不显示的,这样就无法显示所有的列了.解决办法如下: onLoadSuccess: f ...
- 将Android studio的工程导入到eclipse中
自从Android Studio(后面称AS)推出后,越来越多的项目都使用AS开发. AS往eclipse迁移的方法: 其实很简单,代码都是一样的,从AS工程中找到与Eclipse工程对应的文件,放到 ...
- position:relative和z-index解决元素边框重合小bug
由于margin-left:-1;导致一边重合造成以上情况. 解决方法:给元素增加position:relative样式,且给选中的样式增加z-index:1;高于其他未选中元素即可解决.
- ugui中实现圆形按钮
实现圆形按钮,原本是使用 alphHitTestMinimumThreshold 改成重载IsRaycastLocationValid来实现,直接贴代码 using UnityEngine; usin ...
- Redis几个认识误区(转)
add by zhj: 文章很老了,2010年的,注意,下面几点是作者认为的误区 原文:http://timyang.net/data/redis-misunderstanding/ 前几天微博发生了 ...