1.用户使用username和password登陆html
2.系统验证这个password对于该username是正确的java
3.假设第二步验证成功,获取该用户的上下文信息(如他的角色列表)web
4.围绕该用户创建安全上下文(security context)spring
5.用户可能继续进行的一些操做被一个验证控制机制潜在的管理,这个验证机制会根据当前用户的安全上下文来验证权限。浏览器
认证过程就是又前三项构成的。在Spring Security中是这样处理这三部分的:安全
1.username和password被得到后封装到一个UsernamePasswordAuthenticationToken(Authentication接口的实例)的实例中服务器
2.这个token被传递给AuthenticationManager进行验证cookie
3.成功认证后AuthenticationManager将返回一个获得完整填充的Authentication实例app
4.经过调用SecurityContextHolder.getContext().setAuthentication(...),参数传递authentication对象,来创建安全上下文(security context)框架
能够从一个示例代码中观察整个过程(完整代码参考Spring-Security文档9.3.1节):
1 public class AuthenticationExample { 2 3 private static AuthenticationManager am = new SampleAuthenticationManager(); 4 5 public static void main(String[] args) throws Exception { 6 7 String name = ""; 8 String password = ""; 9 try { 10 // request就是第一步,使用name和password封装成为的token 11 Authentication request = new UsernamePasswordAuthenticationToken(name, password); 12 // 将token传递给Authentication进行验证 13 Authentication result = am.authenticate(request); 14 SecurityContextHolder.getContext().setAuthentication(result); 15 break; 16 } catch (AuthenticationException e) { 17 System.out.println("认证失败:" + e.getMessage()); 18 } 19 System.out.println("认证成功,Security context 包含:" + SecurityContextHolder.getContext().getAuthentication()); 20 } 21 } 22 23 // 自定义验证方法 24 class SimpleAuthenticationManager implements AuthenticationManager { 25 static final List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>(); 26 27 // 构建一个角色列表 28 static { 29 AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER")); 30 } 31 32 // 验证方法 33 public Authentication authenticate(Authentication auth) throws AuthenticationException { 34 // 这里咱们自定义了验证经过条件:username与password相同就能够经过认证 35 if (auth.getName().equals(auth.getCredentials())) { 36 return new UsernamePasswordAuthenticationToken(auth.getName(), auth.getCredentials(), AUTHORITIES); 37 } 38 // 没有经过认证则抛出密码错误异常 39 throw new BadCredentialsException("Bad Credentials"); 40 } 41 }
考虑一个典型的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必须处理如下异常:
这些异常应该按照顺序抛出,(好比若是一个帐户被锁定,那么不进行帐户认证)。
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