Board logo

标题: Spring Security 的 Web 应用和指纹登录实践(1) [打印本页]

作者: look_w    时间: 2018-12-13 18:16     标题: Spring Security 的 Web 应用和指纹登录实践(1)

前言Java 开发人员在解决 Web 应用安全相关的问题时,通常会采用两个非常流行的安全框架,Shiro 和 Spring                                Security。Shiro 配置简单,上手快,满足一般应用的安全需求,但是功能相对单一。Spring Security 安全粒度细,与                                Spring Framework 无缝集成,满足绝大多数企业级应用的安全需求,但是配置复杂,学习曲线陡峭。
Spring Security 相对 Shiro 功能强大,并且 Spring Framework,Spring Boot,Spring                                Cloud 对 Spring Security 的支持更加友好 (毕竟是 "亲儿子")。本文将介绍 Spring Security                                的架构设计、核心组件,在 Web 应用中的开发方式,最后以一个指纹登录的实例收尾。
Spring                                Security 核心设计Spring Security                                有五个核心组件:SecurityContext、SecurityContextHolder、Authentication、Userdetails                                和 AuthenticationManager。下面分别介绍一下各个组件。
SecurityContextSecurityContext 即安全上下文,关联当前用户的安全信息。用户通过 Spring Security                                的校验之后,SecurityContext 会存储验证信息,下文提到的 Authentication                                对象包含当前用户的身份信息。SecurityContext 的接口签名如清单 1 所示:
清单 1.                                        SecurityContext                                的接口签名
1
2
3
4
public interface SecurityContext extends Serializable {
       Authentication getAuthentication();
       void setAuthentication(Authentication authentication);
}




SecurityContext 存储在 SecurityContextHolder 中。
SecurityContextHolderSecurityContextHolder 存储 SecurityContext 对象。SecurityContextHolder                                是一个存储代理,有三种存储模式分别是:
SecurityContextHolder 默认使用 MODE_THREADLOCAL 模式,SecurityContext                                存储在当前线程中。调用 SecurityContextHolder 时不需要显示的参数传递,在当前线程中可以直接获取到                                SecurityContextHolder 对象。但是对于很多 C                                端的应用(音乐播放器,游戏等等),用户登录完毕,在软件的整个生命周期中只有当前登录用户,面对这种情况                                SecurityContextHolder 更适合采用 MODE_GLOBAL 模式,SecurityContext                                相当于存储在应用的进程中,SecurityContext 在所有线程中都相同。
AuthenticationAuthentication 即验证,表明当前用户是谁。什么是验证,比如一组用户名和密码就是验证,当然错误的用户名和密码也是验证,只不过                                Spring Security 会校验失败。Authentication 接口签名如清单 2 所示:
清单 2.                                        Authentication                                的接口签名
1
2
3
4
5
6
7
8
public interface Authentication extends Principal, Serializable {
       Collection<? extends GrantedAuthority> getAuthorities();
       Object getCredentials();
       Object getDetails();
       Object getPrincipal();
       boolean isAuthenticated();
       void setAuthenticated(boolean isAuthenticated);
}




Authentication 是一个接口,实现类都会定义                                authorities,credentials,details,principal,authenticated                                等字段,具体含义如下:
在验证前,principal 填充的是用户名,credentials 填充的是密码,detail 填充的是用户的 IP                                或者经纬度之类的信息。通过验证后,Spring Security 对 Authentication 重新注入,principal                                填充用户信息(包含用户名、年龄等), authorities 会填充用户的角色信息,authenticated 会被设置为                                true。重新注入的 Authentication 会被填充到 SecurityContext 中。
UserDetailsUserDetails 提供 Spring Security 需要的用户核心信息。UserDetails 的接口签名如清单 3 所示:
清单 3. UserDetails                                        的接口签名
1
2
3
4
5
6
7
8
9
public interface UserDetails extends Serializable {
       Collection<? extends GrantedAuthority> getAuthorities();
       String getPassword();
       String getUsername();
       boolean isAccountNonExpired();
       boolean isAccountNonLocked();
       boolean isCredentialsNonExpired();
       boolean isEnabled();
}




UserDetails 用 isAccountNonExpired,                                        isAccountNonLocked,isCredentialsNonExpired,isEnabled                                表示用户的状态(与下文中提到的                                        DisabledException,LockedException,BadCredentialsException                                相对应),具体含义如下:
UserDetails 也是一个接口,实现类都会继承当前应用的用户信息类,并实现 UserDetails 的接口。假设应用的用户信息类是                                User,自定义的 CustomUserdetails 继承 User 类并实现 UserDetails 接口。
AuthenticationManagerAuthenticationManager 负责校验 Authentication 对象。在 AuthenticationManager 的                                authenticate 函数中,开发人员实现对 Authentication 的校验逻辑。如果 authenticate                                函数校验通过,正常返回一个重新注入的 Authentication 对象;校验失败,则抛出                                AuthenticationException 异常。authenticate 函数签名如清单 4 所示:
清单 4. authenticate                                        函数签名
1
Authentication authenticate(Authentication authentication)throws AuthenticationException;




AuthenticationManager 可以将异常抛出的更加明确:
重新注入的 Authentication 会包含当前用户的详细信息,并且被填充到 SecurityContext 中,这样 Spring                                Security 的验证流程就完成了,Spring Security 可以识别到 "你是谁"。
基本校验流程示例下面采用 Spring Security 的核心组件写一个最基本的用户名密码校验示例,如清单 5 所示:
清单 5. Spring                                        Security                                核心组件伪代码
1
2
3
4
5
6
7
8
AuthenticationManager amanager = new CustomAuthenticationManager();
Authentication namePwd = new CustomAuthentication(“name”, “password”);
try {
       Authentication result = amanager.authenticate(namePwd);
       SecurityContextHolder.getContext.setAuthentication(result);
} catch(AuthenticationException e) {
       // TODO 验证失败
}




Spring Security 的核心组件易于理解,其基本校验流程是: 验证信息传递过来,验证通过,将验证信息存储到                                SecurityContext 中;验证失败,做出相应的处理。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0