Spring Security 是基于 Spring 的身份认证(Authentication)和用户授权(Authorization)框架,提供了一套 Web 应用安全性的完整解决方案。其中核心技术使用了 Servlet 过滤器、IOC 和 AOP 等
身份认证身份认证指的是用户去访问系统资源时,系统要求验证用户的身份信息,用户身份合法才访问对应资源。常见的身份认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。
用户授权当身份认证通过后,去访问系统的资源,系统会判断用户是否拥有访问该资源的权限,只允许访问有权限的系统资源,没有权限的资源将无法访问,这个过程叫用户授权。比如 会员管理模块有增删改查功能,有的用户只能进行查询,而有的用户可以进行修改、删除。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。
在类上添加注解 @Confifiguration 标识为配置类、 @EnableWebSecurity 启动 SpringSecurity 过滤器链功能。
重写一下两个方法 confifigure(AuthenticationManagerBuilder auth) 身份认证管理器 认证信息提供方式(用户名、密码、当前用户的资源权限)可采用内存存储方式,也可能采用数据库方式等 confifigure(HttpSecurity http) 资源权限配置(过滤器链) 拦截的哪一些资源资源所对应的角色权限定义认证方式: httpBasic 、 httpForm定制登录页面、登录请求地址、错误处理方式自定义 spring security 过滤器等 定义com.sse.security.config.PasswordEncoderConfig类实例化 BCryptPasswordEncoder。BCryptPasswordEncoder类是 PasswordEncoder接口的一个实现类, PasswordEncoder接口有一下几个方法。
NO方法描述1String encode(CharSequence rawPassword);用于加密明文2boolean matches(CharSequence rawPassword, String encodedPassword);输入的密码与数据库中的密码对比3default boolean upgradeEncoding(String encodedPassword) { return false; }是否需要编码,一般不需要。在这里创建一个配置类,将 BCryptPasswordEncoder实例注入容器后,需要使用的时候直接从容器中获取,这样比较方便。代码如下:
@Configuration public class PasswordEncoderConfig { @Bean public PasswordEncoder passwordEncoder() { // 明文+随机盐值加密存储 return new BCryptPasswordEncoder(); } } 明文密码加盐值加密的最终结果分为两部分,盐值 + MD5(password+盐值), 调用 matches(…) 方法的时候,先从密文中得到盐值,用该盐值加密明文和最终密文作对比。这样可以避免有一个密码被破解, 其他相同的密码的帐户都可以破解.因为通过当前机制相同密码生成的密文都不一样。
加密过程(注册): aaa (盐值) + 123(密码明文) > 生成密文 > 最终结果 盐值.密文:aaa.asdlkf 存入数据库校验过程(登录): aaa (盐值, 数据库中得到) + 123(用户输入密码)> 生成密文 aaa.asdlkf,与数据库对比一致密码正确。
这种认证方式,会在浏览器的上方弹出登录窗口,这样不是很美观。详细配置如下:
/** * 认证管理器: * 1、认证信息提供方式(用户名、密码、当前用户的资源权限) * 2、可采用内存存储方式,也可能采用数据库方式等 * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 数据库存储的密码必须是加密后的,不然会报错:There is no PasswordEncoder mapped for the id "null" String password = passwordEncoder.encode("1234"); log.info("加密之后存储的密码:" + password); // 设置用户名和角色 auth.inMemoryAuthentication().withUser("admin") .password(password).authorities("ADMIN"); } /** * 资源权限配置(过滤器链): * 1、被拦截的资源 * 2、资源所对应的角色权限 * 3、定义认证方式:httpBasic 、httpForm * 4、定制登录页面、登录请求地址、错误处理方式 * 5、自定义 spring security 过滤器 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { // 采用 httpBasic认证方式 http.httpBasic() // 表单登录方式 .and() // 认证请求 .authorizeRequests() .anyRequest() //所有访问该应用的http请求都要通过身份认证才可以访问 .authenticated() ; // 注意不要少了分号 }在 sse-security-web工程下创建 MainController类,认证通过就访问这里。
启动后在浏览器访问:http://localhost:8080/index
输入用户名:admin和密码:1234,就可以访问到资源。
将 http.httpBasic()替换成 http.formLogin()就行了。
启动后在浏览器访问:http://localhost:8080/index,访问路径会自动跳转到login路径,验证通过后又跳转到当初访问的路径。
当前版本号:bd91e527929e4f42797df1ab0ba0f1657734f988”
直接在资源配置类中添加 loginPage(String loginPage)方法指定就可以了,但是需要注意:现在拦截的是所有全部请求,自定义一个登录请求,需要将这个地址设置为不认证也可以访问。如果不这样设置,页面会提示“重定向次数过多”。因为登录的时候会访问“login"l路径,设置新的登录地址后,一直来访问新的这个地址,但是这个地址必须登录才可以访问,所以一直循环这样调用,就会出现重定向次数过多。设置如下:
访问登录页面的时候,需要跳转到“login/page"地址,但是没有这个登录也。所以需要在创建这个路径,否则会提示404找不到这个路径。
还可以放行所有静态资源,如果是那些前后端没有分离的项目,所有前端的静态资源都保存在代码中,如果不放行这些静态资源,没有登录时不能访问的。配置如下:
有的时候,前端提交的用户名和密码的名称,就是根据名称获取前端的用户名和密码的这个名称。如果不喜欢使用默认的,也是可以更改。
默认的用户名变量名:username,密码变量名:password。
可以通过 usernameParameter(String usernameParameter)和 passwordParameter(String passwordParameter)方法更改。
当前版本号:04d73e4ae03a52af9d16d087e3ae2c968965fa95
将登录地址、密码和用户名称这些值设置为动态配置的,在代码中去配置不是很理想。直接在yml或者properties文件中动态配置比较乐观,现在就更改为这样的配置方式。
创建 com.sse.security.properites.SecurityProperties配置文件映射类,在创建 com.sse.security.properites.AuthenticationProperties保存配置信息类。
在配置文件中就可以直接调用配置类,获取配置信息就行了。
有些程序登录会做一些非同寻常的操作,那么可以创建一个登录成功处理类。主要关注的是 org.springframework.security.web.authentication.AuthenticationSuccessHandler这个接口,但是我为了能够实现返回JSON格式数据还是重定向地址,我就实现这个接口的实现类,SavedRequestAwareAuthenticationSuccessHandler。
创建 CustomAuthenticationSuccessHandler类,并继承 SavedRequestAwareAuthenticationSuccessHandler类,实现 onAuthenticationSuccess方法,在这个方法里面就可以做一些登录成功需要处理的数据。
在 SpringSecurityConfig中配置 successHandler并指定成功处理类就可以生效了。
判断是返回JSON格式数据还是重定向地址呢?我们直接在配置文件中就可以指定了。
实现效果和成功处理类差不多,只是关注的接口不一样。主要关注 org.springframework.security.web.authentication.AuthenticationFailureHandler接口,为了方便我就实现该接口的实现类 SimpleUrlAuthenticationFailureHandler,并重写 onAuthenticationFailure方法。
在SpringSecurityConfig中配置failureHandler方法指定失败处理类就行了。
全部配置文件如下:
sse: security: authentication: loginPage: /login/page # 响应认证(登录)页面的URL loginProcessingUrl: /login/form # 登录表单提交处理的url usernameParameter: name # 登录表单提交的用户名的属性名 passwordParameter: pwd # 登录表单提交的密码的属性名 loginType: JSON staticPaths: # 静态资源 "/dist/**", "/modules/**", "/plugins/**" - /dist/** - /modules/** - /plugins/**如果你设置为返回JSON格式的数据,那么在浏览器上访问的最初那个地址就不在执行。
当前版本号:f3f1ae3d5327316cfad3b93c9c65a20627fc6608
源码地址:https://github.com/gl-stars/springSecurity-example.git