SpringSecurity:认证和自定义登陆界面
Posted 散漫的大学生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringSecurity:认证和自定义登陆界面相关的知识,希望对你有一定的参考价值。
目录
配置
配置初始化器
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer
//不用重写任何内容
//这里实际上会自动注册一个Filter,SpringSecurity底层就是依靠N个过滤器实现的
创建一个配置类用于配置 SpringSecurity
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
//继承WebSecurityConfigurerAdapter,之后会进行配置
在初始化器中把该配置类添加进去
@Override
protected Class<?>[] getRootConfigClasses()
return new Class[]RootConfiguration.class, SecurityConfiguration.class;
解决中文乱码问题
在初始化器添加,要在进入过滤链之前设置编码方式
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer
@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext)
servletContext.addFilter("CharacterEncodingFilter", new CharacterEncodingFilter("utf-8", true))
.addMappingForUrlPatterns(null, false, "/*");
//super.beforeSpringSecurityFilterChain(servletContext);
认证
要实现登录功能,就需要用户认证
直接认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//这里使用SpringSecurity提供的BCryptPasswordEncoder
auth
.inMemoryAuthentication() //直接验证方式
.passwordEncoder(encoder) //密码加密器
.withUser("test") //用户名
.password(encoder.encode("123456")) //这里需要填写加密后的密码
.roles("user"); //用户的角色
SpringSecurity 的密码校验并不是直接使用原文进行比较,而是使用加密算法将密码进行加密,而且这个过程是不可逆的,然后将用户提供的密码以同样的方式加密后与密文进行比较,保存也是密文,所以即使数据库被窃取了也无法得知密码是多少,很好地保证了用户信息的安全性。
使用数据库认证
需要创建一个 Service 来实现 接口UserDetailsService,它支持我们自己返回一个 UserDetails 对象,我们只需直接返回一个包含数据库中的用户名、密码等信息的 UserDetails 即可,SpringSecurity 会自动进行比对,在配置类中进行扫描并将其注册为 Bean
@Service
public class UserAuthService implements UserDetailsService
@Resource
UserMapper mapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException
String password = mapper.getPasswordByUsername(s); //从数据库根据用户名获取密码
if(password == null)
throw new UsernameNotFoundException("登录失败,用户名或密码错误!");
return User //这里需要返回UserDetails,SpringSecurity会根据给定的信息进行比对
.withUsername(s)
.password(password) //直接从数据库取的密码
.roles("user") //用户角色
.build();
最后再修改一下 Security 配置类
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth
.userDetailsService(service) //使用自定义的Service实现类进行验证
.passwordEncoder(new BCryptPasswordEncoder()); //依然使用BCryptPasswordEncoder
自定义登录界面
替换默认的登陆界面
首先来看一下Spring Security的自定义界面,包含了一个重要的东西
<input
name="_csrf"
type="hidden"
value="83421936-b84b-44e3-be47-58bb2c14571a"
/>
他是隐藏的,为了防止 CSRF 攻击而存在的。
从 Spring Security 4.0 开始,默认情况下会启用 CSRF 保护,以防止 CSRF 攻击应用程序,Spring Security CSRF 会针对 PATCH,POST,PUT 和 DELETE 方法的请求(不仅仅只是登陆请求,这里指的是任何请求路径)进行防护。在不带_csrf的情况下,页面中只要发起了 PATCH,POST,PUT 和 DELETE 请求一定会被拒绝,并返回403错误
需要在请求的时候加入 csrfToken ,也就是"83421936-b84b-44e3-be47-58bb2c14571a",正是 csrfToken,如果提交的是表单类型的数据,那么表单中必须包含此 Token 字符串,键名称为"\\_csrf";如果是 JSON 数据格式发送的,那么就需要在请求头中包含此 Token 字符串。
如果用的是Thymeleaf视图解析器,可以加一个这样的输入框
<input
type="text"
th:name="$_csrf.getParameterName()"
th:value="$_csrf.token"
hidden
/>
Token 的键名称和 Token 字符串可以通过 Thymeleaf 从 Model 中获取,SpringSecurity 会自动将 Token 信息添加到 Model 中
然后就可以配置自己的登陆界面了
先重写Security 配置类中的另一个configure方法
@Override
protected void configure(HttpSecurity http) throws Exception
http
.authorizeRequests() //首先需要配置哪些请求会被拦截,哪些请求必须具有什么角色才能访问
.antMatchers("/static/**").permitAll() //静态资源,使用permitAll来运行任何人访问(注意一定要放在前面)
.antMatchers("/**").hasRole("user") //所有请求必须登陆并且是user角色才可以访问(不包含上面的静态资源)
配置拦截规则,也就是当用户未登录时,哪些路径可以访问,哪些路径不可以访问,如果不可以访问,那么会被自动重定向到登陆页面。
接着需要配置表单登陆和登录页面
.formLogin() //配置Form表单登陆
.loginPage("/login") //登陆页面地址(GET)
.loginProcessingUrl("/doLogin") //form表单提交地址(POST)
.defaultSuccessUrl("/index") //登陆成功后跳转的页面,也可以通过Handler实现高度自定义
.permitAll() //登陆页面也需要允许所有人访问
登陆页面需要我们自己去编写 Controller 来实现,登陆请求提交处理由 SpringSecurity 提供,只需要写路径就可以了。
@RequestMapping("/login")
public String login()
return "login";
再需要配置一下退出登录操作
.and()
.logout()
.logoutUrl("/logout") //退出登陆的请求地址
.logoutSuccessUrl("/login"); //退出后重定向的地址
注意这里的退出登陆请求也必须是 POST 请求方式(因为开启了 CSFR 防护,需要添加 Token),否则无法访问
<body>
<form action="logout" method="post">
<input type="text" th:name="$_csrf.getParameterName()" th:value="$_csrf.token" hidden>
<button>退出登陆</button>
</form>
</body>
关闭csrf防护
直接在配置类中配置
.and()
.csrf().disable();
《SpringSecurity框架专题》-04认证流程分析
我们前面实现了使用自定义认证界面的功能,但是后台认证校验还是使用的’/login’来处理的,对比的账号密码还是我们写在内存的数据,那我们如果想要实现和数据库中的数据比较,那么我们就必须要实现自定义认证逻辑的实现,本文我们就先来分析下系统自带的认证是怎么走的。
1.UsernamePasswordAuthenticationFilter
系统认证是通过UsernamePasswordAuthenticationFilter
过滤器实现的,所以我们需要来分析下这个过滤器的源码
1.1.表单提交参数
1.2.doFilter方法
因为UsernamePasswordAuthenticationFilter
就是一个过滤器,所以我们要分析他的原理,肯定需要通过doFilt
以上是关于SpringSecurity:认证和自定义登陆界面的主要内容,如果未能解决你的问题,请参考以下文章
[SpringSecurity]web权限方案_用户认证_自定义用户登录页面
《SpringSecurity框架专题》-03实现自定义登录界面
Spring Security4实战与原理分析视频课程( 扩展+自定义)