.pom文件需要引入
<!--springboot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
配置中的URL不要入库,csrf token 默认是true
spring boot 的spring security配置代替spring mvc的spring security xxx.xml配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private WebFilterSecurityInterceptor webFilterSecurityInterceptor;
@Bean
UserDetailsService customUserService(){ //注册UserDetailsService 的bean
return new CustomUserService();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserService()); //user Details Service验证
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); // 禁用csrf token
http.authorizeRequests()
.anyRequest().authenticated() //任何请求,登录后可以访问
.and().authorizeRequests().antMatchers("/?logout").permitAll().anyRequest()
.hasAnyRole("ANONYMOUS").and()
.formLogin()
.loginPage("/")
.loginPage("/login")
.failureUrl("/login?error")
.and()
.logout().logoutUrl("/?logout")
.permitAll(); //注销行为任意访问
http.addFilterBefore(webFilterSecurityInterceptor, FilterSecurityInterceptor.class); }}
拦截器实现,根据需求实现。若之前的数据表和spring security不兼容,可以更具数据表的情况,对所有requestUrl放行,拦截特定的url。这里去掉实现逻辑。
@Service
public class WebFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
@Autowired
private FilterInvocationSecurityMetadataSource securityMetadataSource;
@Autowired
public void setMyAccessDecisionManager(WebAccessDecisionManager webAccessDecisionManager) {
super.setAccessDecisionManager(webAccessDecisionManager);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
//fi里面有一个被拦截的url
//里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
//再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
//执行下一个拦截器
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}catch ( Exception e ){
e.printStackTrace();
}
finally {
super.afterInvocation(token, null);
}
}
@Override
public void destroy() {
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
}
加载已有requestUrl
@Service
public class WebInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {
@Autowired
private IPermission permissionService;
private HashMap<String, Collection<ConfigAttribute>> map = null;
/**
* 加载权限表中所有权限
*/
public void loadResourceDefine() {
map = new HashMap<>();
Collection<ConfigAttribute> array;
ConfigAttribute cfg;
List<Permission> permissions =null;
JSONArray permissionArray=null;
try {
permissions=permissionService.getMenuList(1);
} catch ( Exception e ) {
e.printStackTrace();
}
for (Permission permission : permissions) {
array = new ArrayList<>();
cfg = new SecurityConfig(permission.getName());
//此处只添加了用户的名字,其实还可以添加更多权限的信息,例如请求方法到ConfigAttribute的集合中去。此处添加的信息将会作为MyAccessDecisionManager类的decide的第三个参数。
array.add(cfg);
//用权限的getUrl() 作为map的key,用ConfigAttribute的集合作为 value,
map.put(permission.getHref(), array);
}
}
//此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
if (map == null) loadResourceDefine();
//object 中包含用户请求的request 信息
HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
AntPathRequestMatcher matcher;
String resUrl;
for (Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
resUrl = iter.next();
if (resUrl!=null) {
matcher = new AntPathRequestMatcher(resUrl);
if (matcher.matches(request)) {
return map.get(resUrl);
}
}
}
return null;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
判断是否放行的地方,这里对所有requestUrl都放行,拦截器处控制重写
@Service
public class WebAccessDecisionManager implements AccessDecisionManager {
// decide 方法是判定是否拥有权限的决策方法,
//authentication 是释CustomUserService中循环添加到 GrantedAuthority 对象中的权限信息集合.
//object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
//configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
if (null == configAttributes || configAttributes.size() <= 0) {
return;
}
ConfigAttribute c;
String needRole;
for (Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
c = iter.next();
needRole = c.getAttribute();
for (GrantedAuthority ga : authentication.getAuthorities()) {//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合
if (needRole.trim().equals(ga.getAuthority())) {
return;
}
}
}
throw new AccessDeniedException("no right");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
获取登陆用户权限列表,对重写拦截器是鸡肋。
@Service
public class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口
@Autowired
IUser userService;
@Autowired
IPermission permissionService;
public UserDetails loadUserByUsername(String username) {
User user = null;
try {
user = userService.oneByName(username);
} catch ( Exception e ) {
e.printStackTrace();
}
if (user != null) {
List<Permission> permissions = null;
//**此处需将JSONArray菜单列表转化成List<Permission>
try {
permissions = permissionService.getMenuList(user.getId());
} catch ( Exception e ) {
e.printStackTrace();
}
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
for (Permission permission : permissions) {
if (permission != null && permission.getName() != null) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
//1:此处将权限信息添加到 GrantedAuthority 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。
grantedAuthorities.add(grantedAuthority);
}
}
return new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(), grantedAuthorities);
} else {
throw new UsernameNotFoundException("admin: " + username + " do not exist!");
}
}
}
注:拦截器中执行特定的拦截和403 跳转。