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;  
}  
  
}

跨域时需要指定域名,不要用*号*

同理配置一下自定义逻辑处理即可