文档章节

spring security3 实现自定义管理权限

w
 wangxinxx
发布于 2017/03/26 06:03
字数 1411
阅读 73
收藏 1

今天有个群友问了下ss3的问题,他主要是登陆实现权限的校验的顺序不清晰,当初我学这个框架的时候也是被ss3登陆校验权限的顺序困扰了几天。下面是我一点理解,有错的话还望指正一下。

 

其实,要实现自定义权限的话只有几个关键的类和接口,只要搞清楚他们的顺序就行了。

1、你可以初始化话容器的时候就加载资源和权限列表,这个在实现FilterInvocationSecurityMetadataSource接口的类里,定一个全局的静态map,以url为key,所需权限(集合)为value,装进这个静态map。

 

2、登陆。登陆的action在spring配置文件里配好。这个action会直接到继承UsernamePasswordAuthenticationFilter类的一个重写的attemptAuthentication方法里,把你输入username和password(加入配了MD5加密security3会自动帮你加密)和数据比对,如果存在这个username和password,进入第3步(这是后没有退出这个attemptAuthentication方法)。没有这个username和password的话直接抛异常和终止此次登陆。

 

3、如果username和password存在,会进入到实现UserDetailsService接口的类里的一个重写的loadUserByUsername方法,这个方法里会把该username所有拥有的权限设为安全权限然后返回一个UserDetails类型的结果。这是返回到第二步中的attemptAuthentication中,把这这个认证了得安全实体有所拥有的权限以Authentication类型返回。共第五步调用。

 

4、登陆认证成功后会有一个action(这个action在spring配置文件里配置),这个action是第一个url权限认证(假设这个action需要权限认证),这个请求会进入到实现了FilterInvocationSecurityMetadataSource接口的类里的一个重写的getAttributes方法,将第1步中的资源权限列表map中get出来,返回Collection<ConfigAttribute>类型的结果,共第5部调用。

 

5,第4步执行完之后会进入实现类AccessDecisionManager接口的类的一个重写decide方法,在这个方法中会将第3步中返回的Authentication和第4步中返回的Collection<ConfigAttribute>进行比对。比对成功则可以访问,比对不成功会跳转一个页面(这个页面也是在spring配置文件中配置)。

 

至此,已经完成了登陆的验证并成功执行一个action。

 

当然,你可以在登陆成功后添加一些你自己业务,比如说记录登陆次数和登陆ip,这需要实现security3的一些接口,并配置在spring配置文件里。

 

下面是所用到的一些关键的类

1、实现了FilterInvocationSecurityMetadataSource接口的类

 

/**
* @Description : 描述
* @author YangXuan
*@email 364105996@qq.com
* @date Aug 6, 2013 8:56:44 PM
*/
public class MySecurityMetadataSource implements
		FilterInvocationSecurityMetadataSource {

	public MySecurityMetadataSource(ResourcesDao resourcesDao, RolesDao rolesDao) {
		this.resourcesDao = resourcesDao;
		this.rolesDao = rolesDao;
		this.loadResourceDefine();
	}

	private ResourcesDao resourcesDao;
	private RolesDao rolesDao;
	private RequestMatcher requestMatcher;
	private String matcher = "ant";

	public ResourcesDao getResourcesDao() {
		return resourcesDao;
	}

	public void setResourcesDao(ResourcesDao resourcesDao) {
		this.resourcesDao = resourcesDao;
	}

	public RolesDao getRolesDao() {
		return rolesDao;
	}

	public void setRolesDao(RolesDao rolesDao) {
		this.rolesDao = rolesDao;
	}

	public void setRequestMatcher(RequestMatcher requestMatcher) {
		this.requestMatcher = requestMatcher;
	}

	public void setMatcher(String matcher) {
		this.matcher = matcher;
	}

	// 返回所请求资源所需要的权限
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		HttpServletRequest request = ((FilterInvocation) object).getRequest();
		String requestUrl = ((FilterInvocation) object).getRequestUrl();
		System.out.println("requestUrl is " + requestUrl);
		if (resourceMap == null) {
			loadResourceDefine();
		}

		Set<String> urlMatch = resourceMap.keySet();
		for (String url : urlMatch) {
			if (matcher.toLowerCase().equals("ant")) {
				requestMatcher = new AntPathRequestMatcher(url);
			}
			if (matcher.toLowerCase().equals("regex")) {
				requestMatcher = new RegexRequestMatcher(url,
						request.getMethod(), true);
			}
			if (requestMatcher.matches(request)) {
				return resourceMap.get(url);
			}
		}
		return null;
	}

	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return null;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}

	public static Map<String, Collection<ConfigAttribute>> resourceMap = null;

	private void loadResourceDefine() {
		System.out
				.println(">>>>>>>>>>loadResourceDefine()---successfully<<<<<<<<<<");
		if (resourceMap == null) {
			resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
			List<Resources> resources = this.resourcesDao.findAllResources();
			for (Resources resource : resources) {
				/*System.out.println(resource.getId() + "---" + resource.getUrl()
						+ "---" + resource.getDescr() + "---"
						+ resource.isEnabled());*/
				List<Roles> roles = this.rolesDao
						.findRolesByResourcesId(resource.getId());
				Collection<ConfigAttribute> configAttributes = new HashSet<ConfigAttribute>();
				for (Roles role : roles) {
					configAttributes
							.add(new SecurityConfig(role.getRoleName()));
				}
				resourceMap.put(resource.getUrl(), configAttributes);
			}
		}
	}
}

 

 

2、继承了UsernamePasswordAuthenticationFilter的类

 

/**
* @Description : 描述
* @author YangXuan
*@email 364105996@qq.com
* @date Aug 6, 2013 8:57:45 PM
*/
public class MyUsernamePasswordAuthenticationFilter extends
		UsernamePasswordAuthenticationFilter {
	// 定义从前台接收参数的 属性名称
	private String validationParameter = "validation";

	public void setValidationParameter(String validationParameter) {
		this.validationParameter = validationParameter;
	}

	private boolean openValidation = true;

	public void setOpenValidation(boolean openValidation) {
		this.openValidation = openValidation;
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
		if (!request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException(
					"Authentication method not supported: "
							+ request.getMethod());
		}

		String username = obtainUsername(request).trim();
		String password = obtainPassword(request).trim();

		// 验证码validation是否正确
		if (openValidation) {
			checkValidateCode(request);
		}

		// 实现 Authentication,这里装进去的password会通过spring的MD5加密,然后实现校验
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);
		// 允许子类设置详细属性
		setDetails(request, authRequest);

		// 运行UserDetailsService的loadUserByUsername 再次封装Authentication
		return this.getAuthenticationManager().authenticate(authRequest);
	}

	@Override
	protected String obtainUsername(HttpServletRequest request) {
		Object obj = request.getParameter(getUsernameParameter());
		return null == obj ? "" : obj.toString();
	}

	@Override
	protected String obtainPassword(HttpServletRequest request) {
		Object obj = request.getParameter(getPasswordParameter());
		return null == obj ? "" : obj.toString();
	}

	protected String obtainValidationString(HttpServletRequest request) {
		Object obj = request.getParameter(validationParameter);
		return null == obj ? "" : obj.toString();
	}

	public void checkValidateCode(HttpServletRequest request) {

		String jcaptchaCode = obtainValidationString(request).trim()
				.toUpperCase();		//获取前台的验证码输入值
		if (null == jcaptchaCode || jcaptchaCode.equals(""))
			throw new BadCredentialsException("验证码超时!!!");

		boolean b = CaptchaServiceSingleton.getInstance()
				.validateResponseForID(request.getSession().getId(),
						jcaptchaCode);
		if (!b)
			throw new BadCredentialsException("验证码不匹配!!!");
	}

}


3、实现了UserDetailsService接口的类

 

 

/**
* @Description : 描述
* @author YangXuan
*@email 364105996@qq.com
* @date Aug 6, 2013 8:58:30 PM
*/
public class MyUserDetailServiceImpl implements UserDetailsService {

	private UsersDao usersDao;
	private RolesDao rolesDao;

	public UsersDao getUsersDao() {
		return usersDao;
	}

	public void setUsersDao(UsersDao usersDao) {
		this.usersDao = usersDao;
	}

	public RolesDao getRolesDao() {
		return rolesDao;
	}

	public void setRolesDao(RolesDao rolesDao) {
		this.rolesDao = rolesDao;
	}

	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {

		Users users = this.usersDao.findByName(username);
		Set<GrantedAuthority> grantedAuths = obtionGrantedAuthorities(users);
		users.setAuthorities(grantedAuths);

		return users;
	}

	private Set<GrantedAuthority> obtionGrantedAuthorities(Users user) {
		Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();
		List<Roles> roles = this.rolesDao.findRolesByUsersId(user.getId());
		for (Roles role : roles) {
			grantedAuthorities.add(new SimpleGrantedAuthority(role
					.getRoleName()));
		}
		return grantedAuthorities;
	}
}


4、实现了AccessDecisionManager接口的类

 

 

/**
* @Description : 描述
* @author YangXuan
*@email 364105996@qq.com
* @date Aug 6, 2013 8:59:02 PM
*/
public class MyAccessDecisionManager implements AccessDecisionManager {

	public void decide(Authentication authentication, Object object,
			Collection<ConfigAttribute> configAttributes)
			throws AccessDeniedException, InsufficientAuthenticationException {
		if (configAttributes == null) {
			return;
		}
		Iterator<ConfigAttribute> iterator = configAttributes.iterator();
		while (iterator.hasNext()) {
			ConfigAttribute configAttribute = iterator.next();
			String needPermission = configAttribute.getAttribute();
			for (GrantedAuthority ga : authentication.getAuthorities()) {
				if (needPermission.equals(ga.getAuthority())) {
					return;
				}
			}
		}
		// 没有权限让我们去捕捉
		throw new AccessDeniedException(" No authority to access!");
	}

	public boolean supports(ConfigAttribute attribute) {
		return true;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}

}


敲这些文字敲得好辛苦啊……不喜勿喷哈

本文转载自:http://lib.csdn.net/article/javaee/2620

w
粉丝 10
博文 59
码字总数 17566
作品 0
呼和浩特
程序员
私信 提问
《Spring Security3》第四章第二部分翻译(JdbcDaoImpl的高级配置)

JdbcDaoImpl的高级配置 JdbcDaoImpl拥有众多的可配置选项使其可以在已存在的schema中使用,或对其功能进行更复杂地调整。在很多场景下,很可能我们只需调整内置UserDetailsService类的配置而...

heroShane
2014/02/08
70
0
《Spring Security3》第二章第一部分翻译

本文为转载学习 原文链接:http://lengyun3566.iteye.com/blog/1078173 第二章 Spring Security起步 在本章中,我们将要学习Spring Security背后的核心理念,包括重要的术语和产品架构。我们...

heroShane
2014/02/03
163
0
spring-security3 配置和使用

最近项目中要使用到spring-security,闲来没事就研究了下。发现入门挺简单的,在这里把自己的心得发下,希望对没有接触过想接触的朋友有帮助。 1、在spring-security官网下载最新jar然后拷贝...

blooms
2012/09/18
998
2
spring-security3 配置和使用.

1、在spring-security官网下载最新jar然后拷贝jar到项目的lib下。 2、在classpath下添加security配置文件,例如applicationContext-security.xml.网上现在大多都是2.0的schema. 要根据自己使用...

长平狐
2012/11/28
2K
0
spring security3.x学习(20)_初探authorize标签和第四个例子

本文为转载学习 原文链接:http://blog.csdn.net/dsundsun/article/details/11880743 第四个例子也就是spring security3那本书中的第五章的例子。 csdn下载:http://download.csdn.net/deta...

heroShane
2014/02/02
131
0

没有更多内容

加载失败,请刷新页面

加载更多

读书笔记:深入理解ES6 (五)

第五章 解构:使数据访问更便捷 第1节 为什么使用解构功能?   在ES5中,开发者们从对象、数组中获取特定数据并赋值给变量,编写了很多看起来同质化的代码。例如: 1 let options = {2 ...

张森ZS
3分钟前
0
0
CentOS7 yum方式安装MySQL5.7

在CentOS中默认安装有MariaDB,这个是MySQL的分支,但为了需要,还是要在系统中安装MySQL,而且安装完成之后可以直接覆盖掉MariaDB。 1 下载并安装MySQL官方的 Yum Repository [root@localho...

roockee
12分钟前
2
0
Allegro三种自定义设置快捷键的方法

Allegro自定义设置快捷键的三种方法: 1、在Allegro PCB editor 命令窗口直接定义 2、通过修改用户变量env文件来设置快捷键 3、定义笔画为快捷键 1、在Allegro PCB editor 命令窗口直接定义 ...

demyar
16分钟前
0
0
如何做一张能让人眼前一亮的大屏?

作为在职场驰骋的社会人,提到数据可视化大家应该都不陌生了。数据可视化的作用也不用我多说,主要是利用图形化手段,更清晰直观地将数据展示。多层次、交互式的可视化分析能够方便决策者理解...

朕想上头条
17分钟前
0
0
TL138/1808/6748-EthEVM开发板硬件CPU、FLASH、RAM

TL138/1808/6748-EthEVM是广州创龙基于SOM-TL138/1808/6748核心板开发的一款开发板,具有三个网络接口。由于SOM-TL138/1808/6748核心板管脚兼容,所以此三个核心板共用同一个底板。开发板采用...

Tronlong创龙
21分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部