springBoot2.X+spring security5.3.8+redis整合用户登录权限控制
- 主要功能点介绍
- 重要代码片段
主要功能点介绍
1.权限过滤
2.改造attemptAuthentication,重写该方法目的在于支持JSON格式提交登录信息。
3.验证后的返回信息均实现相应接口重写相应方法,以JSON格式返回前端。
4.会话管理,session并发控制过滤器,限制同一账号同时登录数量。
5.针对集群部署场景,通过redis实现session共享。
重要代码片段
package com.hexy.hexy_umagt.config;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import com.hexy.hexy_umagt.config.security.AnonymousAuthenticationEntryPoint;
import com.hexy.hexy_umagt.config.security.CustomConcurrentSessionFilter;
import com.hexy.hexy_umagt.config.security.DefaultUserDetailsService;
import com.hexy.hexy_umagt.config.security.InvalidSessionHandler;
import com.hexy.hexy_umagt.config.security.LoginFailureHandler;
import com.hexy.hexy_umagt.config.security.LoginSuccessHandler;
import com.hexy.hexy_umagt.config.security.LoginUserAccessDeniedHandler;
import com.hexy.hexy_umagt.config.security.LogoutSuccessHandler;
import com.hexy.hexy_umagt.config.security.MyAuthenticationProvider;
import com.hexy.hexy_umagt.config.security.MyConcurrentSessionControlAuthenticationStrategy;
import com.hexy.hexy_umagt.config.security.MyUsernamePasswordAuthenticationFilter;
import com.hexy.hexy_umagt.config.security.RestHttpSessionIdResolver;
import com.hexy.hexy_umagt.config.security.SessionInformationExpiredHandler;
/**
* 支持JSON登录提交,返回json数据(同时支持表单提交验证)
* session并发控制,只允许一个用户同时在线。
* @author hxy
*
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DefaultUserDetailsService userDetailsService;
/**
* 登出成功的处理
*/
@Autowired
private LoginFailureHandler loginFailureHandler;
/**
* 登录成功的处理
*/
@Autowired
private LoginSuccessHandler loginSuccessHandler;
/**
* 登出成功的处理
*/
@Autowired
private LogoutSuccessHandler logoutSuccessHandler;
/**
* 未登录的处理
*/
@Autowired
private AnonymousAuthenticationEntryPoint anonymousAuthenticationEntryPoint;
/**
* 超时处理
*/
@Autowired
private InvalidSessionHandler invalidSessionHandler;
/**
* 顶号处理
*/
@Autowired
private SessionInformationExpiredHandler sessionInformationExpiredHandler;
/**
* 登录用户没有权限访问资源
*/
@Autowired
private LoginUserAccessDeniedHandler accessDeniedHandler;
@Autowired
private MyAuthenticationProvider authenticationProvider;
@Resource
private SessionRegistry sessionRegistry;
/**
* 配置认证方式等
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider);
}
/**
* http相关的配置,包括登入登出、异常处理、会话管理等
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.authorizeRequests()
// 放行接口
.antMatchers("/register","/login").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
// 异常处理(权限拒绝、登录失效等)
.and().exceptionHandling()
.authenticationEntryPoint(anonymousAuthenticationEntryPoint)//匿名用户访问无权限资源时的异常处理
.accessDeniedHandler(accessDeniedHandler)//登录用户没有权限访问资源
// 登入
.and().formLogin().permitAll()//允许所有用户
// .successHandler(loginSuccessHandler)//登录成功处理逻辑
// .failureHandler(loginFailureHandler)//登录失败处理逻辑
// 登出
.and().logout().permitAll()//允许所有用户
.logoutSuccessHandler(logoutSuccessHandler)//登出成功处理逻辑
.deleteCookies(RestHttpSessionIdResolver.AUTH_TOKEN)
// 会话管理
.and().sessionManagement();
// .sessionAuthenticationStrategy(concurrentSession());
// .invalidSessionStrategy(invalidSessionHandler) // 超时处理
// .maximumSessions(1)//同一账号同时登录最大用户数
// .expiredSessionStrategy(sessionInformationExpiredHandler); // 顶号处理;
http.addFilterAt(myAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
//session并发控制过滤器
http.addFilterAt(concurrentSessionFilter(), ConcurrentSessionFilter.class);
}
//在全局中注入Bean:(Spring Security 提供了BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用BCrypt强)
@Bean
public BCryptPasswordEncoder bcryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
//SpringSecurity内置的session监听器
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
@Bean()
MyUsernamePasswordAuthenticationFilter myAuthenticationFilter() throws Exception {
//自定义登录验证获取用户名密码方式兼容JSON及表单提交
MyUsernamePasswordAuthenticationFilter filter = new MyUsernamePasswordAuthenticationFilter();
//自定义json上送登录信息时,重新登录方法改变默认的getParameter获取,解析json获取,同时重定向登录成功需要重新set
filter.setAuthenticationSuccessHandler(loginSuccessHandler);
filter.setAuthenticationFailureHandler(loginFailureHandler);
filter.setAuthenticationManager(authenticationManager());
//session并发控制,因为默认的并发控制方法是空方法.这里必须自己配置一个
//不可这么写----》filter.setSessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry()));
//错误点,这里一定要引用自己重写的session(否则后面是取不到principals的,无论如何都是null)
filter.setSessionAuthenticationStrategy(concurrentSession());
return filter;
}
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Bean
public CompositeSessionAuthenticationStrategy concurrentSession() {
// ConcurrentSessionControlAuthenticationStrategy concurrentAuthenticationStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
MyConcurrentSessionControlAuthenticationStrategy concurrentAuthenticationStrategy = new MyConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
concurrentAuthenticationStrategy.setMaximumSessions(1);
// concurrentAuthenticationStrategy.setExceptionIfMaximumExceeded(true);
List<SessionAuthenticationStrategy> delegateStrategies = new ArrayList<SessionAuthenticationStrategy>();
delegateStrategies.add(concurrentAuthenticationStrategy);
delegateStrategies.add(new SessionFixationProtectionStrategy());
delegateStrategies.add(new RegisterSessionAuthenticationStrategy(sessionRegistry()));
CompositeSessionAuthenticationStrategy authenticationStrategy = new CompositeSessionAuthenticationStrategy(delegateStrategies);
return authenticationStrategy;
}
@Bean()
ConcurrentSessionFilter concurrentSessionFilter() {
CustomConcurrentSessionFilter concurrentSessionFilter = new CustomConcurrentSessionFilter(sessionRegistry(), sessionInformationExpiredHandler);
return concurrentSessionFilter;
}
}
以上片段仅展示所有功能点,具体重写内容可通过git了解。代码均已上传,且已验证过。
session共享使用redis主要要启动注解
@Slf4j
@EnableTransactionManagement
@MapperScan("com.hexy.hexy_umagt.mapper")
@SpringBootApplication
@EnableDubbo
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)//session共享redis实现
public class HexyUmagtApplication {
public static void main(String[] args) {
SpringApplication.run(HexyUmagtApplication.class, args);
}
}
所有重写的实现类就不直接贴出来,详情见GIt吧。
GIT地址:https://gitee.com/hellohexiaoyu/commonframework
最后说明下整个security框架其实还是比较繁琐的,不注意时会遇到很多棘手问题,网络上有很多博客,但是提供的内容不一定适用自己,所以遇到问题还是要多看源码,先理解整个框架运行原理。剩下的问题基本都会迎刃而解。