【阿里小哥告诉我】SpringSecurity与自动登录,注销登录的爱恨情仇
程序员文章站
2024-03-19 15:02:04
...
首先我们要明白,自动登录就是把我们的登录信息保存到客户端也就是浏览器的cookie中,当我们下次再访问某个网站时,自动实现登录。从而会想到另外一个层面我们在开发系统是提升了用户登录的体验,但是会潜在的安全隐患。这就为我们主人公SpringSecurity主人公上场做好了铺垫,SpringSecurity提供了两种非常好的令牌:
官方:
1、用散列算法加密用户的登录信息并生成令牌。
2、持久性数据存储机制用的持久化令牌–比如数据库持久性技术
package com.zcw.demospringsecurity.demo8;
import com.zcw.demospringsecurity.demo4.User;
import com.zcw.demospringsecurity.demo4.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
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;
/**
* @ClassName : MyUserDetailsService
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-04-11 16:49
*/
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User byUserName = userMapper.findByUserName(username);
if(byUserName ==null){
throw new UsernameNotFoundException("数据不存在");
}
byUserName.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(byUserName.getRoles()));
return byUserName;
}
}
package com.zcw.demospringsecurity.demo8;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* @ClassName : WebSecurityConfig
* @Description : 方式1:SpringSecurity-散列加密方案实现自动登录
* @Author : Zhaocunwei
* @Date: 2020-04-11 16:55
*/
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/api/**").permitAll()
.anyRequest().authenticated()
.and()
.csrf()
.disable()
.formLogin()
.and()
//增加自动登录功能,默认为简单散列加密 --通过查看源码,默认过期时间为两个星期
.rememberMe().userDetailsService(userDetailsService)
.key("zcw");
/**
* 为什么自定义key,是因为通过查看源代码,
* 在没有指定可以的情况下,系统会默认使用一个UUID字符串
* 同时SpringSecurity在每次表单登录成功之后会更新此令牌,
* 结合我们当下微服务架构盛行,分布式部署架构,如果每次都更新key,
* 就会出现数据不同步问题,造成用户实现自动登录cookie失效,所以在
* 实际项目开发中,我们要合理的创建key
*/
}
}
package com.zcw.demospringsecurity.demo8;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import javax.sql.DataSource;
/**
* @ClassName : MyUserDetailsService2
* @Description :方式2:SpringSecurity-持久性数据存储机制用的持久化令牌
* @Author : Zhaocunwei
* @Date: 2020-04-11 20:48
*/
@EnableWebSecurity
public class WebSecurityConfig2 extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService userDetailsService;
@Autowired
private DataSource dataSourece; //JdbcTokenRepositoryImpl是基于此类实现对应SQL操作的类
@Override
protected void configure(HttpSecurity http) throws Exception{
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSourece);
http.authorizeRequests()
.antMatchers("/admin/**")
.hasAuthority("ROLE_ADMIN")
.antMatchers("/user/**")
.hasRole("USER")
.antMatchers("/app/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.csrf()
.disable()
.formLogin()
.and()
.rememberMe()
.userDetailsService(userDetailsService)
.tokenRepository(jdbcTokenRepository);
}
}
package com.zcw.demospringsecurity.demo8;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ClassName : WebSecurityConfigLogout
* @Description : SpringSecurity实现注销登录
* @Author : Zhaocunwei
* @Date: 2020-04-11 23:08
*/
@EnableWebSecurity
public class WebSecurityConfigLogout extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
/**
* 通过查看源码,我们大家会发现在Logout的清理过程是由多个LogoutHandler流式处理的
*/
http.logout()
//指定接收注销请求的路由
.logoutUrl("/logOut")
//注销成功,重定向到该路径下
.logoutSuccessUrl("/")
//注销成功的处理方式,不同于logoutSuccessUrl的重定向,logoutSuccessHandler
//更加灵活,
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication)
throws IOException, ServletException {
}
})
//使该用户的HttpSession失效
.invalidateHttpSession(true)
//注销成功,删除指定的cookie
.deleteCookies("cookie1", "cookie2")
//用于注销的处理句柄,允许自定义一些清理策略
//事实上LogoutSuccessHandler也能做到
.addLogoutHandler(new LogoutHandler() {
@Override
public void logout(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Authentication authentication) {
}
});
}
}
上一篇: token 能做什么?
下一篇: AJAX跨域问题