spring boot整合spring security4自定义配置

作者 xqlee
浏览次数 824


spring boot整合spring security4自定义配置
1.项目结构图
项目结构图
2.自定义spring拦截器UrlInterceptor
package com.leftso.config;

import org.springframework.web.servlet.HandlerInterceptor;

/**
 * url 拦截器,实现该接口并在实现类上添加注解@Component,将会自动注入spring拦截器
 * 
 * @author leftso
 *
 */

public interface UrlInterceptor extends HandlerInterceptor {
	/***
	 * 需要拦截的url
	 * 
	 * @return
	 */
	String[] pathPatterns();

	/***
	 * 排除拦截
	 * 
	 * @return
	 */
	String[] excludePathPatterns();

	int order();
}
3.获取spring context容器(为了后面动态添加拦截器)
package com.leftso.config;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 
 * <pre>
 * [Summary]
 * 获取spring容器
 * [Detail]
 * TODO
 * [Author]
 * leftso
 * [Version]
 * v1.0
 * 2017年3月23日下午8:59:15
 * </pre>
 */
@Component
public class SpringUtils implements ApplicationContextAware {
	public static ApplicationContext applicationContext = null;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		if (SpringUtils.applicationContext == null) {
			SpringUtils.applicationContext = applicationContext;
		}

	}

}
4.继承WebMvcConfigurerAdapter重写配置,动态添加拦截器
package com.leftso.config;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * 添加自定义的拦截器
 * 
 * @author
 *
 */
@Configuration
public class MvcConfigurerAdapter extends WebMvcConfigurerAdapter {

	@Autowired
	SpringUtils springUtils;

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		super.addInterceptors(registry);
		@SuppressWarnings("static-access")
		Map<String, UrlInterceptor> urlInterceptors = springUtils.applicationContext
				.getBeansOfType(UrlInterceptor.class);
		if (!StringUtils.isEmpty(urlInterceptors)) {
			Set<String> keys = urlInterceptors.keySet();
			Iterator<String> it = keys.iterator();
			while (it.hasNext()) {
				String key = it.next();
				UrlInterceptor urlInterceptor = urlInterceptors.get(key);
				String[] pathPatterns = urlInterceptor.pathPatterns();
				if (pathPatterns == null) {
					pathPatterns = new String[] {};
				}
				String[] excludePathPatterns = urlInterceptor.excludePathPatterns();
				if (excludePathPatterns == null) {
					excludePathPatterns = new String[] {};
				}
				registry.addInterceptor(urlInterceptor).addPathPatterns(pathPatterns)
						.excludePathPatterns(excludePathPatterns);
			}
		}
	}

}
5.从这里开始,进行spring security相关配置,配置启用spring security
package com.leftso.security.config;

import org.springframework.context.annotation.Configuration;
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;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests().anyRequest().permitAll();
	}

	/**
	 * 需要拦截的url
	 * 
	 * @return
	 */
	public String[] securityMethodUrlPatterns() {

		return new String[] { "/security/**" };
	}
}
注意:这里的http.authorizeRequests().anyRequest().permitAll();允许所有访问是为了后面自定义拦截器,不使用默认的spring filter
6.自定义一个spring security认证服务
package com.leftso.security.service;

import javax.servlet.http.HttpServletRequest;

/**
 * spring security 业务处理
 * 
 * @author LEFTSO
 *
 */
public interface SecurityService {
	/**
	 * 获取认证信息
	 * 
	 * @param httpServletRequest
	 */
	public void authenticate(HttpServletRequest httpServletRequest);

	/**
	 * 释放认证信息
	 */
	public void release();
}

接口里面有两个方法,一个是通过请求信息生成认证信息,一个是释放认证信息资源
实现类:
package com.leftso.security.service;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import com.leftso.security.UserAuthentication;

@Component
public class SecurityServiceimp implements SecurityService {

	@Override
	public void authenticate(HttpServletRequest httpServletRequest) {
		// 通过http请求cookie或者其他方式拿到用户登录后的凭证
		String name = httpServletRequest.getParameter("name");
		if ("leftso".equals(name)) {
			// 创建一个认证信息实例
			// 1.创建当前用户的角色信息
			List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
			authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
			// 2.实例创建
			Authentication authentication = new UserAuthentication(authorities, name);
			authentication.setAuthenticated(true);
			// 添加到安全容器
			SecurityContextHolder.getContext().setAuthentication(authentication);
		}else{
			SecurityContextHolder.clearContext();
		}
	}

	@Override
	public void release() {
		SecurityContextHolder.clearContext();
	}

}
这里的认证只是简单的写死了传递一个name参数且值为leftso才会认证成功并且添加一个ROLE_ADMIN的角色,当然实际应用这里应该去数据库查询认证,做好缓存等操作
下面是一个上面用到的自定义认证实现:
package com.leftso.security;

import java.util.Collection;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

/**
 * 自定义用户认证
 * 
 * @author leftso
 *
 */
public class UserAuthentication extends AbstractAuthenticationToken {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String name;

	public UserAuthentication(Collection<? extends GrantedAuthority> authorities) {
		super(authorities);
	}

	public UserAuthentication(Collection<? extends GrantedAuthority> authorities, String name) {
		super(authorities);
		this.name = name;
	}

	@Override
	public Object getCredentials() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object getPrincipal() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getName() {
		return name;
	}

}

7.最重要的入口来了,自定义一个拦截器作为需要安全认证的入口
package com.leftso.security;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;

import com.leftso.config.UrlInterceptor;
import com.leftso.security.config.WebSecurityConfig;
import com.leftso.security.service.SecurityService;

/**
 * spring security安全拦截器
 * 
 * @author leftso
 *
 */
@Component
public class SecurityInterceptor implements UrlInterceptor {

	@Autowired
	WebSecurityConfig abstractWebSecurityConfig;

	@Autowired
	SecurityService securityService;

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception arg3)
			throws Exception {
		// 后置释放认证信息
		securityService.release();

	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView arg3)
			throws Exception {

	}

	@Override
	public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse arg1, Object arg2)
			throws Exception {
		System.out.println("---Security:Interceptor--");
		// 前置处理认证信息
		securityService.authenticate(httpServletRequest);
		return true;
	}

	@Override
	public String[] pathPatterns() {
		// 配置中获取拦截信息
		return abstractWebSecurityConfig.securityMethodUrlPatterns();
	}

	@Override
	public int order() {

		return 0;
	}

	@Override
	public String[] excludePathPatterns() {
		// TODO Auto-generated method stub
		return null;
	}

}
拦截器前置调用获取用户信息生成认证信息
拦截器后置释放认证信息资源
注意前置必须返回TRUE,否则不能继续


8.定义了两个简单的controller用于测试
package com.leftso.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexCtrl {

	@GetMapping("")
	public String index() {
		return "Welcome Index Page.";
	}

	@GetMapping("p1")
	public String p1() {
		return "P1";
	}

	@GetMapping("login")
	public String login() {
		return "Login Page";
	}
}
package com.leftso.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SecurityCtrl {

	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@GetMapping("/security/s1")
	public String s1() {
		return "s1";
	}

	@GetMapping("/security/s2")
	public String s2() {
		return "s2";
	}

}

启动项目:
首页
继续访问受保护的资源链接:
403
由于没有权限,报错403禁止访问,(说明/security/**下面所有资源都会被拦截)

但是访问s2:
222
不难发现可以访问s2,这是为啥呢?
区别
需要保护的资源必须加上需要访问的权限角色


好了言归正传,如何访问到s1的资源呢?如下:
成功访问
说明:实际应用中这个认证的信息是登录后的令牌并且是加密的,可能是放session中可能是cookie中

暂无评论
站内搜索
搜索
广而告之(广告说明)
加入QQ群(641395244)
qq group
支持博客发展
support
推荐博客
暂无推荐
分享本文