您的位置:首页 > 编程语言 > Java开发

spring security3 实现自定义管理权限

2017-03-26 00:00 162 查看
今天有个群友问了下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;
}

}


敲这些文字敲得好辛苦啊……不喜勿喷哈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Spring Security