SSM使用XML文件配置 WEB.xml <!-- 1:DelegatingFilterProxy用于整合第三方框架(代理过滤器,非真正的过滤器,真正的过滤器需要在spring的配置文件) 整合Spring Security时过滤器的名称必须为springSecurityFilterChain, 否则会抛出NoSuchBeanDefinitionException异常 --> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 导入 xml 文件 <!-- 导入security--> <import resource="classpath:spring-security.xml"></import> spring security配置文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:security="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <!--一:定义哪些链接可以放行--> <!-- http:用于定义相关权限控制 指定哪些资源不需要进行权限校验,可以使用通配符 --> <security:http security="none" pattern="/js/**"/> <security:http security="none" pattern="/css/**"/> <security:http security="none" pattern="/img/**"/> <security:http security="none" pattern="/plugins/**"/> <security:http security="none" pattern="/login.html"></security:http> <!--开启注解方式权限控制--> <security:global-method-security pre-post-annotations="enabled"/> <!-- 二:定义哪些链接不可以放行,即需要有角色、权限才可以放行 http:用于定义相关权限控制 auto-config:是否自动配置 设置为true时框架会提供默认的一些配置,例如提供默认的登录页面、登出处理等 设置为false时需要显示提供登录表单配置,否则会报错 use-expressions:用于指定intercept-url中的access属性是否使用表达式 --> <security:http auto-config="true" use-expressions="true"> <!--自定义异常处理--> <security:access-denied-handler ref="customAccessDeniedHandler"/> <security:headers> <!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问--> <security:frame-options policy="SAMEORIGIN"></security:frame-options> </security:headers> <!--只要认证通过就可以访问--> <!-- intercept-url:定义一个拦截规则 pattern:对哪些url进行权限控制 access:在请求对应的URL时需要什么权限,默认配置时它应该是一个以逗号分隔的角色列表, 请求的用户只需拥有其中的一个角色就能成功访问对应的URL isAuthenticated():需要经过认证后才能访问(不是匿名用户) --> <security:intercept-url pattern="/pages/**" access="isAuthenticated()"/> <!-- form-login:定义表单登录信息 --> <security:form-login login-page="/login.html" username-parameter="username" password-parameter="password" login-processing-url="/login.do" default-target-url="/pages/main.html" authentication-failure-url="/login.html" always-use-default-target="true" /> <!-- csrf:对应CsrfFilter过滤器 disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403) --> <security:csrf disabled="true"/> <!-- logout:退出登录 logout-url:退出登录操作对应的请求路径 logout-success-url:退出登录后的跳转页面 --> <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/> </security:http> <!-- 三:认证管理,定义登录账号名和密码,并授予访问的角色、权限 authentication-manager:认证管理器,用于处理认证操作 --> <security:authentication-manager> <!-- authentication-provider:认证提供者,执行具体的认证逻辑 --> <security:authentication-provider user-service-ref="springSecurityUserService"> <!--指定密码加密策略--> <security:password-encoder ref="passwordEncoder"></security:password-encoder> </security:authentication-provider> <!-- <security:authentication-provider>--> <!-- <security:user-service>--> <!-- <security:user name="admin" authorities="ROLE_ADMIN" password="{noop}admin"></security:user>--> <!-- </security:user-service>--> <!-- </security:authentication-provider>--> <!-- </security:authentication-manager>--> <!--配置密码加密对象--> <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/> </beans> 自定义逻辑处理- 查询用户的权限 package com.hl.travel.security; import com.hl.travel.Service.LoginService; import com.hl.travel.Service.UserService; import com.hl.travel.entity.Permission; import com.hl.travel.entity.Role; import com.hl.travel.entity.User; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; 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.Component; import java.util.ArrayList; import java.util.List; import java.util.Set; @Component @RequiredArgsConstructor public class SpringSecurityUserService implements UserDetailsService { private final UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.findUserByUserName(username); if (user == null) { return null; } List<GrantedAuthority> list = new ArrayList<>(); Set<Role> roles = user.getRoles(); for (Role role : roles) { Set<Permission> permissions = role.getPermissions(); for (Permission permission : permissions) { list.add(new SimpleGrantedAuthority(permission.getKeyword())); } } UserDetails userDetails = new org.springframework.security.core.userdetails.User(username, user.getPassword(), list); return userDetails; } } Spring Boot 配置 Java配置文件 package com.hl.travel.config; import com.hl.travel.constant.MessageConstant; import com.hl.travel.security.CustomAccessDeniedHandler; import com.hl.travel.security.SpringSecurityUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; 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.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.Authentication; 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.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.header.writers.frameoptions.WhiteListedAllowFromStrategy; import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter; import org.springframework.security.web.session.HttpSessionEventPublisher; import org.springframework.session.Session; import org.springframework.session.SessionRepository; import org.springframework.session.data.redis.RedisIndexedSessionRepository; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration; import org.springframework.session.security.SpringSessionBackedSessionRegistry; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.Collections; @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true)//开启方法级别的权限控制 @Configuration @EnableRedisHttpSession public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private com.hl.travel.security.SpringSecurityUserService SpringSecurityUserService; // // @Autowired // private RedisIndexedSessionRepository sessionRepository; //配置后端服务 @Override protected void configure(HttpSecurity http) throws Exception { // super.configure(http); http .headers().frameOptions().disable()// 解决 in a frame because it set 'X-Frame-Options' to 'deny' 问题 // 开启允许iframe 嵌套 .and() .cors()//跨域 .configurationSource(corsConfigurationSource()) .and() .authorizeRequests() // 其他请求配置 // .antMatchers(MessageConstant.LOGIN_SUCCESS_URL+"/pages/**").authenticated() // 需要认证才能访问 .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 允许 OPTIONS 请求通过 用于前端跨域请求 预检请求 .antMatchers("/swagger-ui/**").permitAll() // 允许swagger-ui.html请求通过 .antMatchers("/v3/api-docs/**").permitAll() // 允许/v3/api-docs/**请求通过 .anyRequest().authenticated() // 对其他请求进行身份验证 .and() .formLogin() .loginPage(MessageConstant.LOGIN_SUCCESS_URL+"/login.html") // 登录页面 .loginProcessingUrl("/login.do")// 登录请求拦截的url,也就是form表单提交时指定的action .permitAll() // 允许所有用户访问 .successHandler(loginSuccessHandler()) // 使用自定义的登录成功处理器 .failureUrl(MessageConstant.LOGIN_SUCCESS_URL+"/login.html")// 登录失败后跳转的url .and() .logout() .logoutUrl("/logout.do") // 退出登录拦截的url .logoutSuccessUrl(MessageConstant.LOGIN_SUCCESS_URL+"/login.html") // 退出登录成功后跳转的url .and() .rememberMe() // 开启记住我功能 .and() .exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler())//权限不足处理器 .and() .csrf() .disable() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .invalidSessionUrl(MessageConstant.LOGIN_SUCCESS_URL+"/login.html")//session失效后跳转的url .maximumSessions(1)//同一账号同时登录最大用户数 .maxSessionsPreventsLogin(false) // 允许新会话替换旧会话 .sessionRegistry(sessionRegistry());// 使用Redis存储会话信息 } /** * 解决session失效后 sessionRegistry中session没有同步失效的问题,启用并发session控制,首先需要在配置中增加下面监听器 * @return */ @Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); } /** * 注册bean sessionRegistry */ @Bean public SessionRegistry sessionRegistry() { return new SessionRegistryImpl(); } // @Bean // public SpringSessionBackedSessionRegistry sessionRegistry() { // return new SpringSessionBackedSessionRegistry<>(sessionRepository); // } // 静态资源放行 配置前端服务 @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/css/**"); web.ignoring().antMatchers("/js/**"); web.ignoring().antMatchers("/fonts/**"); web.ignoring().antMatchers("/img/**"); web.ignoring().antMatchers("/plugins/**"); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //inMemoryAuthentication 从内存中获取 // auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("admin").password(new BCryptPasswordEncoder().encode("admin")).roles("ADMIN"); //注入userDetailsService的实现类 auth.userDetailsService(SpringSecurityUserService).passwordEncoder(new BCryptPasswordEncoder()); } @Bean public AuthenticationSuccessHandler loginSuccessHandler() { return new SavedRequestAwareAuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { // 自定义登录成功后的处理逻辑 //保存一份到前端域名 response.setHeader("Access-Control-Allow-Credentials", "true"); // 允许携带cookie跨域 // 例如,重定向到前端页面的URL // response.sendRedirect(MessageConstant.LOGIN_SUCCESS_URL+"/pages/main.html"); response.sendRedirect(MessageConstant.LOGIN_SUCCESS_URL+"/pages/main.html"); } }; } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowCredentials(true); // 允许携带cookie跨域 configuration.setAllowedOrigins(Arrays.asList(MessageConstant.LOGIN_SUCCESS_URL,MessageConstant.LOGIN_FRONT_URL)); // 允许所有域名进行跨域调用 configuration.setAllowedMethods(Collections.singletonList("*")); // 允许所有请求方法跨域调用 configuration.setAllowedHeaders(Collections.singletonList("*")); // 允许所有请求头跨域调用 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); // 对所有请求路径进行跨域设置 return source; } } 跨域时需要指定域名,不要用*号* 同理配置一下自定义逻辑处理即可