赞
踩
SpringSecurity分为两种
它们都有默认的页面来使用。
1. 首先我们需要创建配置类,此类需要加上@EnableWebSecurity证明 启动springSecurity过滤链功能,需要重写两个方法
/** 身份认证过滤器 2. 认证信息提供方式(用户名,密码,当前用户的资源权限) 3. 可采的内存存储方式,也可采用数据库方式等。 */ configure(AuthenticationManagerBuilder auth); /** 资源权限配置(过滤器链) 4. 拦截哪些资源 5. 资源所对应的角色权限 3. 定义认证方式 httpbasic httpform 6. 定制登录页面,登录请求地址,错误处理方式 7. 自定义 springsecurity 过滤器等 */ configure(HttpSecurity http)
2. 我们先了解HttpBasic认证方式
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and()
.authorizeRequests()//认证请求
.anyRequest().authenticated() //所有进入应用的http请求都要进行认证
;
}
使用HttpBasic 认证方式, 会使用security默认的账号和密码,账号为user 密码 是会自动生成一个
3. 基于内存存储认证信息
上面的用户名和密码是security为我们提供的,下面基于内存存储自定义的用户名密码。
//使用这两个方法来指定账号 密码
withUser("andy")//账号
password("1234")//密码
3.1 重启后报错
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
这时查看下 PasswordEncoder 的源码
public interface PasswordEncoder {
// 用于明文加密
// 我们来调用,一般在注册的时候,将前端传过来的密码,进行加密后保存进数据库
String encode(CharSequence var1);
// 输入密码与数据库密码进行对比
// 明文与密文的对比
boolean matches(CharSequence var1, String var2);
//是否需要再次进行编码增加安全性,默认不需要
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
注:
3.2 解决错误
指定BCryptPasswordEncoder加密方式相同的密码, 在每次加密后的结果都不一样的,因为它每次都会随机生成盐值, 会将随机生成的盐加到密码串中
每次判断时, 通过随机生成的盐反推回加密时的密码串, 最终判断是否匹配
加密的最终结果分为两部分,盐值 + MD5(password+盐值), 调用 matches(…) 方法的时候,先从密文中得到
盐值,用该盐值加密明文和最终密文作对比,
这样可以避免有一个密码被破解, 其他相同的密码的帐户都可以破解.因为通过当前机制相同密码生成的密文都
不一样。
加密过程(注册): aaa (盐值) + 123(密码明文) > 生成密文 > 最终结果 盐值.密文:aaa.asdlkf 存入数据库
校验过程(登录): aaa (盐值, 数据库中得到) + 123(用户输入密码)> 生成密文 aaa.asdlkf,与数据库对比一
致密码正确
4. httpform 表单认证方式
底层代码了解
spring security采用过滤器链实现认证与授权
//BasicAuthenticationFilter 中的 BasicAuthenticationConverter.convert 方法
-- 152UsernamePasswordAuthenticationToken authRequest = authenticationConverter.convert(request);
//获取请求头 Authorization
-- 80 String header = request.getHeader(AUTHORIZATION);
//判断是否存在 basic
-- 86 if (!StringUtils.startsWithIgnoreCase(header, AUTHENTICATION_SCHEME_BASIC)) {
return null;
}
// 大致是 这样 basic username:password 封装,在进行basic64 编码,拿到封装的数据在进行解码,再取对应的username 和password
-- 107 int delim = token.indexOf(":");
if (delim == -1) {
throw new BadCredentialsException("Invalid basic authentication token");
}
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(token.substring(0, delim), token.substring(delim + 1));
//如果抛错 进入ExceptionTranslationFilter
-- 118 chain.doFilter(request, response); //会直接放行,抛错在cache中会捕获,会进行重定向
//FilterSecurityInterceptor
//核心方法invoke 这里会根据config 中配置的对应权限再次进行鉴权,如果没有对应的可访问资源 那就会抛出异常
-- 123 InterceptorStatusToken token = super.beforeInvocation(fi);
打上对应断点,我们来跟一下,
重启后 localhost/index 进入 FilterSecurityInterceptor invoke方法
why?
//对于UsernamePasswordAuthenticationFilter 来说它只接收 /login方法
-- 62 public UsernamePasswordAuthenticationFilter() {
super(new AntPathRequestMatcher("/login", "POST"));
}
//所以直接放行,进入FilterSecurityInterceptor
//而目前config中设置的也是对所有的请求进行认证,所以当前的/index 访问会被拦截,
//抛错到ExceptionTranslationFilter cache中会重定向到登录页面。
这时候显示默认的登录页面
输入用户名以及密码,进入UsernamePasswordAuthenticationFilter
//他会构造一个token
-- 89 UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
//进入 UsernamePasswordAuthenticationToken 中 核心方法
//首次进入会置为false 无权限
-- 58 setAuthenticated(false);
//认证 username password 匹配
--95 return this.getAuthenticationManager().authenticate(authRequest);
//再次进入FilterSecurityInterceptor 放行
下面是我的security学习demo ,感兴趣的可以看下
GitHub :https://github.com/Andy-leoo/mxg-security.git
下面是 spring security中文文档,大家可以看看
https://www.springcloud.cc/spring-security-zhcn.html#what-is-acegi-security
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。