一.简介
这篇文章来学习下security的认证方式其中的HTTP摘要认证
二.Spring Security的认证方式
2.1什么是认证
认证:
就是用来判断系统中是否存在某用户,并判断该用户的身份是否合法的过程,解决的其实是用户登录的问题。认证的存在,是为了保护系统中的隐私数据与资源,只有合法的用户才可以访问系统中的资源。
2.2认证的方式
在Spring Security中,常见的认证方式可以分为HTTP层面和表单层面,常见的认证方式如下:
- HTTP基本认证;
- Form表单认证
- HTTP摘要认证;
这篇文章先讲HTTP摘要认证
三. HTTP摘要认证
3.1Form表单认证简介
HTTP摘要认证和HTTP基本认证一样,也是在RFC2616中定义的一种认证方式,它的出现是为了弥补HTTP基本认证存在的安全隐患,但该认证方式也并不是很安全。HTTP摘要认证会使用对通信双方来说都可知的口令进行校验,且最终以密文的形式来传输数据,所以相对于基本认证来说,稍微安全了一些。
3.2HTTP摘要认证模型
HTTP摘要认证与基本认证类似,基于简单的“挑战-回应”模型。当我们发起一个未经认证的请求时,服务器会返回一个401回应,并给客户端返回与验证相关的参数,期待客户端依据这些参数继续做出回应,从而完成整个验证过程。
3.3HTTP摘要认证核心参数
服务端给客户端返回的验证相关参数如下:
- username: 用户名。
- password: 用户密码。
- realm: 认证域,由服务器返回。
- opaque: 透传字符串,客户端应原样返回。
- method: 请求的方法。
- nonce: 由服务器生成的随机字符串,包含过期时间(默认过期时间300s)和密钥。
- nc: 即nonce-count,指请求的次数,用于计数,防止重放攻击。qop被指定时,nc也必须被指定。
8.cnonce: 客户端发给服务器的随机字符串,qop被指定时,cnonce也必须被指定。 - qop: 保护级别,客户端根据此参数指定摘要算法。若取值为 auth,则只进行身份验证;若取值为auth-int,则还需要校验内容完整性,默认的qop为auth。
- uri: 请求的uri。
- response: 客户端根据算法算出的摘要值,这个算法取决于qop。
- algorithm: 摘要算法,目前仅支持MD5。
- entity-body: 页面实体,非消息实体,仅在auth-int中支持。
通常服务器端返回的数据包括realm、opaque、nonce、qop等字段,如果客户端需要做出验证回应,就必须按照一定的算法得到一些新的数据并一起返回。在以上各种参数中,对服务器而言,最重要的字段是nonce;对客户端而言,最重要的字段是response。
四. 创建SpringSecurity项目
参考之前的文章,这边不做叙述。
五.代码实现
5.1创建SecurityConfig配置类
创建SecurityConfig类,继承自WebSecurityConfigurerAdapter父类,该类的作用如下:
- 验证所有请求;
- 允许用户使用表达登录进行身份验证;
- 允许用户使用Http基本认证。
代码如下:
@EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DigestAuthenticationEntryPoint digestAuthenticationEntryPoint;
@Autowired
private MyUserDetailsService userDetailsService;
//配置认证入口端点,主要是设置认证参数信息
@Bean
public DigestAuthenticationEntryPoint digestAuthenticationEntryPoint(){
DigestAuthenticationEntryPoint point=new DigestAuthenticationEntryPoint();
point.setKey("Security Demos");
point.setRealmName("demaxiya");
point.setNonceValiditySeconds(500);
return point;
}
public DigestAuthenticationFilter digestAuthenticationFilter(){
DigestAuthenticationFilter filter=new DigestAuthenticationFilter();
filter.setAuthenticationEntryPoint(digestAuthenticationEntryPoint);
filter.setUserDetailsService(userDetailsService);
return filter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**")
.hasRole("ADMIN")
.antMatchers("/user/**")
.hasRole("USER")
.antMatchers("/visitor/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.csrf()
.disable()
//当未认证时访问某些资源,则由该认证入口类来处理.
.exceptionHandling()
.authenticationEntryPoint(digestAuthenticationEntryPoint)
.and()
//添加自定义过滤器到过滤器链中
.addFilter(digestAuthenticationFilter());
}
}
5.2创建web接口
IndexController 类的代码如下:
@RestController
public class IndexController {
@GetMapping("/admin/hello")
public String helloAdmin() {
return "hello, admin";
}
@GetMapping("/user/hello")
public String helloUser() {
return "hello, user";
}
@GetMapping("/visitor/hello")
public String helloVisitor() {
return "hello, visitor";
}
}
5.3yml配置文件
创建一个application.yml配置文件,配置如下:
spring:
security:
user:
name: demaxiya
password: 123
5.4MyUserDetailService 类
MyUserDetailService类的代码如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Service
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.loadUserByUserName(username);
if (Objects.isNull(user)) {
throw new UsernameNotFoundException("user is null");
}
user.setRoles(userMapper.getRolesByUid(user.getId()));
return user;
}
}
六.功能验证
6.1启动项目
接着来访问一下需要认证的接口,比如/admin/hello接口,这时候会发现浏览器弹出了一个用户名密码的认证窗口。然后我们在浏览器中可以看到HTTP摘要认证信息,realm是我们自定义的“demaxiya”,qop是默认的“auth”方式。截图如下:
由此可见,此时摘要认证的方式已经生效。
七.HTTP摘要认证弊端
HTTP摘要认证与HTTP基本认证一样,都是基于HTTP层面的认证方式,也不能使用Session对象,因而也不支持Remember-Me功能。该方式虽然解决了HTTP基本认证中以明文传输密码的问题,但并未解决密码明文存储的问题,所以依然有安全隐患,所以在开发中,摘要认证的方式也不怎么使用。