Authentication讲解(Spring security认证)
标准认证过程:
1.用户使用username和password登录
2.系统验证这个password对于该username是正确的
3.假设第二步验证成功,获取该用户的上下文信息(如他的角色列表)
4.围绕该用户建立安全上下文(security context)
5.用户可能继续进行的一些操作被一个验证控制机制潜在的管理,这个验证机制会根据当前用户的安全上下文来验证权限。
认证过程就是又前三项构成的。在Spring Security中是这样处理这三部分的:
1.username和password被获得后封装到一个UsernamePasswordAuthenticationToken(Authentication接口的实例)的实例中
2.这个token被传递给AuthenticationManager进行验证
3.成功认证后AuthenticationManager将返回一个得到完整填充的Authentication实例
4.通过调用SecurityContextHolder.getContext().setAuthentication(...),参数传递authentication对象,来建立安全上下文(security context)
可以从一个示例代码中观察整个过程(完整代码参考Spring-Security文档9.3.1节):
public class AuthenticationExample {
private static AuthenticationManager am = new SampleAuthenticationManager();
public static void main(String[] args) throws Exception {
String name = "";
String password = "";
try {
// request就是第一步,使用name和password封装成为的token
Authentication request = new UsernamePasswordAuthenticationToken(name, password);
// 将token传递给Authentication进行验证
Authentication result = am.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
break;
} catch (AuthenticationException e) {
System.out.println("认证失败:" + e.getMessage());
}
System.out.println("认证成功,Security context 包含:" + SecurityContextHolder.getContext().getAuthentication());
}
}
// 自定义验证方法
class SimpleAuthenticationManager implements AuthenticationManager {
static final List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>();
// 构建一个角色列表
static {
AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER"));
}
// 验证方法
public Authentication authenticate(Authentication auth) throws AuthenticationException {
// 这里我们自定义了验证通过条件:username与password相同就可以通过认证
if (auth.getName().equals(auth.getCredentials())) {
return new UsernamePasswordAuthenticationToken(auth.getName(), auth.getCredentials(), AUTHORITIES);
}
// 没有通过认证则抛出密码错误异常
throw new BadCredentialsException("Bad Credentials");
}
}
Web Application
考虑一个典型的Web应用认证过程:
1.访问首页,随便点击一个链接
2.发送一个请求到服务器,服务器判断你是否在访问一个收到保护的资源
3.此时你还没有进行认证,服务器会返回一个响应告诉你必须先通过认证。这个响应可以是一个HTTP响应码或者是重定向到指定的web页面
4.根据认证机制,你的浏览器可能会重定向到一个登录页面,或者通过某种方式恢复你的身份(通过一个基础的认证对话框,cookie,X.509证明等)
5.浏览器回应服务器。这可以是一个HTTP POST请求,包含你所填写的表单信息,也可以是一个HTTP请求头,包含你的认证详情
6.接下来服务器会判定提交的凭证是否通过认证。如果认证通过,那么继续下一步。如果没有通过认证,那么重新进行上边的步骤
7.你在认证之前,原始的请求(即触发认证的请求)将会重新发起。
Spring Security已经实现了上述的大多数过程。主要有ExceptionTranslationFilter,AuthenticationEntryPoint和一个认证机制,负责调用上面讨论过的AuthenticationManager。
ExceptionTranslationFilter:
ExceptionTranslationFilter是用来检测Spring Security抛出的任何异常的过滤器。
AuthenticationProvider和UserDetails:
There is often some confusion about UserDetailsService. It is purely a DAO for user data and performs no other function other than to supply that data to other components within the framework. In particular, it does not authenticate the user, which is done by the AuthenticationManager. In many cases it makes more sense to implement AuthenticationProvider directly if you require a custom authentication process.
UserDetailsService经常有些困惑。它纯粹是用户数据的一个DAO,除了将该数据提供给框架内的其他组件之外,没有其他功能。特别是,它不验证用户,这是由身份验证管理器完成的。在许多情况下,如果需要自定义身份验证过程,直接执行身份验证提供程序就更有意义。
AuthenticationManager:
用来处理一个认证请求。只有一个authentication(Authentication authentication)函数。
尝试去认证传入的Authentication对象,如果认证成功,返回一个完整填充的Authentication对象(包括授予的权限)。
一个AuthenticationManager必须处理以下异常:
- DisabledException:当一个账户被禁用且AuthenticationManager可以检测出来这个状态,要抛出该异常
- LockedException:当一个账户被锁且AuthenticationManager可以检测这个状态,要抛出该异常
- BadCredentialsException:当账户认证失败,必须抛出该异常。(一个AuthenticationManager必须检测这个状态)
这些异常应该按照顺序抛出,(比如如果一个账户被锁定,那么不进行账户认证)。
AuthenticationProvider:
用来处理一个指定的认证。有一个authenticate(Authentication authentication)函数和一个supports(Class<?> authentication)函数。
其中authenticate函数的用法与AuthenticationManager的authenticate一样。
supports函数用来指明该Provider是否适用于该类型的认证,如果不合适,则寻找另一个Provider进行验证处理。
ProviderManager:
通过AuthenticationProviders迭代认证请求。
AuthenticationProviders通常按照顺序尝试,直到返回一个不为null的响应。非空响应代表provider可以提供认证并且不会继续请求下一个provider。如果后边的provider成功进行了验证,那么前边provider抛出的异常将被忽略。
CustomUserDetail代码(java)
public class CustomUserDetail implements UserDetails {
private User user;
private List<SimpleGrantedAuthority> authorities = new ArrayList<>();
public CustomUserDetail() {}
public CustomUserDetail(User user, List<Role> roles) {
this.user = user;
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getCode()));
System.out.println("Role:" + role.getCode());
}
}
public String getName() {
return user.getName();
}
public User getUser() {
return user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getMobile();
}
@Override
public boolean isAccountNonExpired() {
return user.getEnabled();
}
@Override
public boolean isAccountNonLocked() {
return user.getEnabled();
}
@Override
public boolean isCredentialsNonExpired() {
return user.getEnabled();
}
@Override
public boolean isEnabled() {
return user.getEnabled();
}
}
CustomUserDetailService代码(java)
public class CustomUserDetailService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Autowired
RoleMapper roleMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userMapper.getUserByMobile(s);
if (user != null) {
List<Role> roles = roleMapper.getRolesByUserId(user.getId());
return new CustomUserDetail(user, roles);
} else {
throw new UsernameNotFoundException("用户不存在");
}
}
}
CustomAuthenticationProvider代码(java)
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private CustomUserDetailService userDetailService;
@Override//Authentication中封装了username和password
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = (String)authentication.getCredentials();//Credential证书
UserDetails userDetails = userDetailService.loadUserByUsername(username);
String md5Pwd = DigestUtils.md5DigestAsHex(password.getBytes());
if (userDetails.getPassword().equals(md5Pwd)) {
return new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
} else {
throw new BadCredentialsException("密码错误");
}
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
本博客引用自:https://www.cnblogs.com/shiyu404/p/6530894.html
Authentication讲解(Spring security认证)的更多相关文章
- Authentication(Spring Security 认证笔记)
这篇文章是对Spring Security的Authentication模块进行一个初步的概念了解,知道它是如何进行用户认证的 考虑一个大家比较熟悉的标准认证过程: 1.用户使用username和pa ...
- Spring Security认证配置(三)
学习本章之前,可以先了解下上篇Spring Security认证配置(二) 本篇想要达到这样几个目的: 1.登录成功处理 2.登录失败处理 3.调用方自定义登录后处理类型 具体配置代码如下: spri ...
- Spring Security认证提供程序
1.简介 本教程将介绍如何在Spring Security中设置身份验证提供程序,与使用简单UserDetailsService的标准方案相比,提供了额外的灵活性. 2. The Authentica ...
- spring security 认证源码跟踪
spring security 认证源码跟踪 在跟踪认证源码之前,我们先根据官网说明一下security的内部原理,主要是依据一系列的filter来实现,大家可以根据https://docs.sp ...
- Spring Security 入门(1-4-1)Spring Security - 认证过程
理解时可结合一下这位老兄的文章:http://www.importnew.com/20612.html 1.Spring Security的认证过程 1.1.登录过程 - 如果用户直接访问登录页面 用 ...
- spring-security-4 (4)spring security 认证和授权原理
在上一节我们讨论了spring security过滤器的创建和注册原理.请记住springSecurityFilterChain(类型为FilterChainProxy)是实际起作用的过滤器链,Del ...
- Spring Security 入门(1-4-2)Spring Security - 认证过程之AuthenticationProvider的扩展补充说明
1.用户信息从数据库获取 通常我们的用户信息都不会向第一节示例中那样简单的写在配置文件中,而是从其它存储位置获取,比如数据库.根据之前的介绍我们知道用户信息是通过 UserDetailsService ...
- Spring Security认证配置(二)
学习本章之前,可以先了解下上篇Spring Security基本配置. 本篇想要达到这样几个目的: 1.访问调用者服务时,如果是html请求,则跳转到登录页,否则返回401状态码和错误信息 2.调用方 ...
- spring security认证
1 开发基于表单的认证 Spring security核心的功能 认证(你是谁?) 授权(你能干什么?) 攻击防护(防止伪造身份) spring security实现了默认的用户名+密码认证,默认用户 ...
随机推荐
- 网络流24题 P1251 餐巾计划问题 拆点
题目描述 一个餐厅在相继的 NN 天里,每天需用的餐巾数不尽相同.假设第 ii 天需要 r_iri块餐巾( i=1,2,...,N).餐厅可以购买新的餐巾,每块餐巾的费用为 pp 分;或者把旧餐巾送 ...
- 10-PI开发手册-ERP发布服务供外围系统调用(RFC类型)
一. 文档信息 版本号* 更新日期* 姓名* 更新内容及更新理由* 备注* V1.0 2019/02/19 fanjb 文档创建 以福利接口13589(Z00HRJ_GJJ_REV_FI ...
- 64位ubuntu安装交叉编译工具链,显示找不到命令
是因为Ubuntu64位版本已不支持ia32-libs的软件包,而是使用了lib32ncurses5.lib32z1软件包做为替代, 所以在Ubuntu16.04版本当中应该安装执行: sudo ap ...
- SQL 之 字符区别(转)
1.CHAR.CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间,不足的自动用空格填充,所以在读取的 ...
- git总结三、关于分支下——团队合作中最重要的合并分支
合并分支是团队合作开发中常见的操作,这里涉及到两个命令:git merge 和 git rebase 下面来好好说一下git merge和git rebase都是怎样工作的 一. 1.新建一个空目录并 ...
- spring 方法验证参数
1:实体使用 @Valid 使用 validation 类注解 2:String 使用 controller 添加 @Validated @NotBlank(message = "i ...
- springboot 配置mybatis
- ftp服务器安装与配置
ftp服务器安装与配置 1. ftp服务端的安装 1 如果之前配置过ftp服务器的还是之后配置的服务器,无法启动服务,那么基本是配置出现了错误,那么可先完全卸载后再进行安装.如果无法定位多半是镜像源的 ...
- SPFA求最短路——Bellman-Ford算法的优化
SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环.SPFA 最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE), ...
- Git-01-上传项目到github
function fun1(){ Git上传项目到github Folder-->Git bash here Execute command: --git clone 仓库地址 多出一个 ...