栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

详解spring security四种实现方式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

详解spring security四种实现方式

spring security实现方式大致可以分为这几种:

    1.配置文件实现,只需要在配置文件中指定拦截的url所需要权限、配置userDetailsService指定用户名、密码、对应权限,就可以实现。

    2.实现UserDetailsService,loadUserByUsername(String userName)方法,根据userName来实现自己的业务逻辑返回UserDetails的实现类,需要自定义User类实现UserDetails,比较重要的方法是getAuthorities(),用来返回该用户所拥有的权限。

    3.通过自定义filter重写spring security拦截器,实现动态过滤用户权限。

    4.通过自定义filter重写spring security拦截器,实现自定义参数来检验用户,并且过滤权限。

1.最简单配置spring-security.xml,实现1

 
 
   
   
   
     roles = new HashSet() ;
   Role role = new Role();
   role.setRoleid("ROLE_USER");
   role.setRoleName("ROLE_USER");
   
   Set resources=new HashSet() ;
   
   Resource res = new Resource();
   res.setResid("ME001");
   res.setResName("首页");
   res.setResUrl("/jsp/index/main.jsp");
   res.setType("ROLE_USER");
   res.setRoles(roles);
   resources.add(res);
   
   role.setResources(resources);
   
   roles.add(role);
     user = new User();
   user.setAccount("admin");
   user.setDisabled(false);
   user.setPassword(PasswordUtils.entryptPassword(Constants.securityKey));
   log.info(user.getPassword());
   user.setRoles(roles);   
   }
   return user;//返回UserDetails的实现user不为空,则验证通过
  }
  
}

UserDetails实现:


package com.ultrapower.me.util.security.entity;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

 
public class User implements UserDetails {
 
 private static final long serialVersionUID = 8026813053768023527L;

  
 private String account;
 
 private String name;
 
 private String password;
 
 private boolean disabled;
 
 private Set roles;
 
 
 private Map> roleResources;
 
 
 public User() {
 
 }
 
 
 public String getAuthoritiesString() {
   List authorities = new ArrayList();
   for(GrantedAuthority authority : this.getAuthorities()) {
     authorities.add(authority.getAuthority());
   }
   return StringUtils.join(authorities, ",");
 }

 @Override
 public Collection getAuthorities() {
 // 根据自定义逻辑来返回用户权限,如果用户权限返回空或者和拦截路径对应权限不同,验证不通过
 if(!roles.isEmpty()){
  List list = new ArrayList();
  GrantedAuthority au = new SimpleGrantedAuthority("ROLE_USER");
  list.add(au);
  return list;
 }
 return null;
 }

 
 public String getPassword() {
 return password;
 }

 
 public String getUsername() {
 return name;
 }

 
 public boolean isAccountNonExpired() {
 return true;
 }

 
 public boolean isAccountNonLocked() {
 return true;
 }

 
 public boolean isCredentialsNonExpired() {
 return true;
 }

 
 public boolean isEnabled() {
 return !disabled;
 }

 

 
 public String getName() {
 return name;
 }

 
 public boolean isDisabled() {
 return disabled;
 }

 
 public Set getRoles() {
 return roles;
 }

 
 public Map> getRoleResources() {
 // init roleResources for the first time
 System.out.println("---------------------------------------------------");
 if(this.roleResources == null) {
  
  this.roleResources = new HashMap>();
  
  for(Role role : this.roles) {
  String roleName = role.getRoleName();
  Set resources = role.getResources();
  for(Resource resource : resources) {
   String key = roleName + "_" + resource.getType();
   if(!this.roleResources.containsKey(key)) {
   this.roleResources.put(key, new ArrayList());
   }
   this.roleResources.get(key).add(resource);   
  }
  }
  
 }
 return this.roleResources;
 }

 
 
 public void setName(String name) {
 this.name = name;
 }

 
 public void setPassword(String password) {
 this.password = password;
 }

 
 public void setDisabled(boolean disabled) {
 this.disabled = disabled;
 }

 
 public void setRoles(Set roles) {
 this.roles = roles;
 }

 public String getAccount() {
 return account;
 }

 public void setAccount(String account) {
 this.account = account;
 }

 public void setRoleResources(Map> roleResources) {
 this.roleResources = roleResources;
 }
 
}

3.实现动态过滤用户权限

在spring-security配置文件的http标签中添加如下配置


在spring-security配置文件中添加如下配置 


 
 
   
   
 

 

 

securityInterceptor继承AbstractSecurityInterceptor过滤器,实现Filter过滤器

package com.ultrapower.me.util.security.interceptor;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.security.access.SecuritymetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecuritymetadataSource;

public class SecurityInterceptor extends AbstractSecurityInterceptor implements Filter{

 //配置文件注入
  private FilterInvocationSecuritymetadataSource securitymetadataSource;
 
 public FilterInvocationSecuritymetadataSource getSecuritymetadataSource() {
 return securitymetadataSource;
 }

 public void setSecuritymetadataSource(
  FilterInvocationSecuritymetadataSource securitymetadataSource) {
 this.securitymetadataSource = securitymetadataSource;
 }

 @Override
 public void doFilter(ServletRequest request, ServletResponse response,
  FilterChain chain) throws IOException, ServletException {
 // TODO Auto-generated method stub
 
 FilterInvocation fi = new FilterInvocation(request, response, chain);
 //fi里面有一个被拦截的url
    //里面调用MyInvocationSecuritymetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
    //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够
    InterceptorStatusToken token = super.beforeInvocation(fi);
    try {
     //执行下一个拦截器
     fi.getChain().doFilter(fi.getRequest(), fi.getResponse());  
    } finally { 
      super.afterInvocation(token, null); 
    }  
 
 }

 @Override
 public void init(FilterConfig arg0) throws ServletException {
 // TODO Auto-generated method stub
 
 }

 @Override
 public Class getSecureObjectClass() {
 // TODO Auto-generated method stub
 return FilterInvocation.class; 
 }

 @Override
 public SecuritymetadataSource obtainSecuritymetadataSource() {
 // TODO Auto-generated method stub
 return this.securitymetadataSource;  
 }

 @Override
 public void destroy() {
 // TODO Auto-generated method stub
 }
}

登陆后,每次访问资源都会被这个拦截器拦截,会执行doFilter这个方法,这个方法调用了invoke方法,其中fi断点显示是一个url(可能重写了toString方法吧,但是里面还有一些方法的),最重要的是beforeInvocation这个方法,它首先会调用MyInvocationSecuritymetadataSource类的getAttributes方法获取被拦截url所需的权限,在调用MyAccessDecisionManager类decide方法判断用户是否够权限。弄完这一切就会执行下一个拦截器。

secureResourceFilterInvocationDefinitionSource实现


package com.ultrapower.me.util.security.interceptor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.ServletContext;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecuritymetadataSource;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;


public class SecureResourceFilterInvocationDefinitionSource implements FilterInvocationSecuritymetadataSource, InitializingBean {
  
  private PathMatcher matcher;
  
  private static Map> map = new HashMap>();

  
  public void afterPropertiesSet() throws Exception {
    this.matcher = new AntPathMatcher();//用来匹配访问资源路径
    Collection atts = new ArrayList(); 
    ConfigAttribute ca = new SecurityConfig("ROLE_USER");
    atts.add(ca); 
    map.put("/jsp/index/main.jsp", atts); 
    Collection attsno =new ArrayList();
    ConfigAttribute cano = new SecurityConfig("ROLE_NO");
    attsno.add(cano);
    map.put("/http://blog.csdn.net/u012367513/article/details/other.jsp", attsno);  
  }
  
   

  @Override
 public Collection getAttributes(Object object)
  throws IllegalArgumentException {
 // TODO Auto-generated method stub
   FilterInvocation filterInvocation = (FilterInvocation) object;
   
   String requestURI = filterInvocation.getRequestUrl();
   //循环资源路径,当访问的Url和资源路径url匹配时,返回该Url所需要的权限
    for(Iterator>> iter = map.entrySet().iterator(); iter.hasNext();) {
      Map.Entry> entry = iter.next();
      String url = entry.getKey();
      
      if(matcher.match(url, requestURI)) {
 return map.get(requestURI);
      }
    }
   
 return null;
 }

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

 
 @SuppressWarnings("rawtypes")
 public Collection getConfigAttributeDefinitions() {
    return null;
  }

  
 public boolean supports(@SuppressWarnings("rawtypes") Class clazz) {
    return true;
  }
  
  
  @SuppressWarnings("unchecked")
 private Map getUrlAuthorities(org.springframework.security.web.FilterInvocation filterInvocation) {
    ServletContext servletContext = filterInvocation.getHttpRequest().getSession().getServletContext();
    return (Map)servletContext.getAttribute("urlAuthorities");
  }

}

mesecurityAccessDecisionManager实现

package com.ultrapower.me.util.security.interceptor;

import java.util.Collection;
import java.util.Iterator;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

public class SecurityAccessDecisionManager implements AccessDecisionManager {
  
 
 @Override
 public void decide(Authentication authentication, Object object,
  Collection configAttributes)
  throws AccessDeniedException, InsufficientAuthenticationException {
 // 对应url没有权限时,直接跳出方法
  if(configAttributes == null){ 
      return;    
    } 
    
    Iterator ite=configAttributes.iterator();
    //判断用户所拥有的权限,是否符合对应的Url权限,如果实现了UserDetailsService,则用户权限是loadUserByUsername返回用户所对应的权限
    while(ite.hasNext()){
      ConfigAttribute ca=ite.next(); 
      String needRole=((SecurityConfig)ca).getAttribute();
      for(GrantedAuthority ga : authentication.getAuthorities()){ 
      System.out.println(":::::::::::::"+ga.getAuthority());
 if(needRole.equals(ga.getAuthority())){ 
   return;
 }      
      }   
    } 
    //注意:执行这里,后台是会抛异常的,但是界面会跳转到所配的access-denied-page页面
    throw new AccessDeniedException("no right"); 
 }
 @Override
 public boolean supports(ConfigAttribute attribute) {
 return true;
 }
 @Override
 public boolean supports(Class clazz) {
 return true;
 }

}

4.实现AuthenticationProvider,自定义参数验证

这种验证以前项目用过,现在没有写示例代码,先写下大概流程和需要用到的类

这种验证的好处:可以在自定义登录界面添加登录时需要的参数,如多个验证码等、可以修改默认登录名称和密码的参数名

整体流程:

1.用户登录时,先经过自定义的passcard_filter过滤器,该过滤器继承了AbstractAuthenticationProcessingFilter,并且绑定了登录失败和成功时需要的处理器(跳转页面使用)

2.执行attemptAuthentication方法,可以通过request获取登录页面传递的参数,实现自己的逻辑,并且把对应参数set到AbstractAuthenticationToken的实现类中

3.验证逻辑走完后,调用 this.getAuthenticationManager().authenticate(token);方法,执行AuthenticationProvider的实现类的supports方法

4.如果返回true则继续执行authenticate方法

5.在authenticate方法中,首先可以根据用户名获取到用户信息,再者可以拿自定义参数和用户信息做逻辑验证,如密码的验证

6.自定义验证通过以后,获取用户权限set到User中,用于springSecurity做权限验证

7.this.getAuthenticationManager().authenticate(token)方法执行完后,会返回Authentication,如果不为空,则说明验证通过

8.验证通过后,可实现自定义逻辑操作,如记录cookie信息

9.attemptAuthentication方法执行完成后,由springSecuriy来进行对应权限验证,成功于否会跳转到相对应处理器设置的界面。

1.自定义PassCardAuthenticationToken类,继承AbstractAuthenticationToken类,用于定义参数,需要实现的方法


 @Override
 public Object getCredentials() {
 return password;
 }

 
 @Override
 public Object getPrincipal() {
 return userID;
 }

2.User类要实现Authentication,需要实现的方法


 @Override
 public Collection getAuthorities() {
 return this.accesses;
 }
 
 @Override
 public Object getCredentials() {
 return null;
 }
 @Override
 public Object getDetails() {
 return null;
 }
 
 @Override
 public Object getPrincipal() {
 return loginName;
 }
 
 @Override
 public boolean isAuthenticated() {
 return this.authenticated;
 }
 
 @Override
 public void setAuthenticated(boolean isAuthenticated)
  throws IllegalArgumentException {
 this.authenticated=isAuthenticated;
 }

3.需要userService实现AuthenticationProvider的 authenticate(Authentication authentication)方法

  @SuppressWarnings("unchecked")
 @Override
 public Authentication authenticate(Authentication authentication)
  throws AuthenticationException {
 PassCardAuthenticationToken token=(PassCardAuthenticationToken)authentication;
 
 if(token.getUserID()!=null&&token.getPassword()!=null){
  User user=(User)this.getDao().executeQueryUnique("User.loadByLoginName", QueryCmdType.QUERY_NAME, token.getUserID());
  
  String password=token.getPassword();
  if(this.passwordEncoder!=null){
  password=this.passwordEncoder.encodePassword(password, null);
  }
  
  if(!password.equalsIgnoreCase(user.getPassword())){
  
  token.setErrCode("2");
  return null;
  }
  
  if( token.isEnablePasscard() && usePassCard ){//token中激活密码卡且系统使用密码卡
  
  int position1=((token.getRow1()-1)*7)+token.getColumn1();
  int position2=((token.getRow2()-1)*7)+token.getColumn2();
  //System.out.println( "---pos:"+position1+"---"+position2 );
  
  if(user.getPassCardId()==null){
   token.setErrCode("10");
   return null;
  }
  PassCard passcard=this.passCardDao.findById(user.getPassCardId(), false);
   
  if(passcard==null||passcard.getStatus()==PassCardHelper.STATUS_CANCEL ){
   token.setErrCode("10");
   return null;
  }
  if(passcard.getConfusedContent()==null || passcard.getConfusedContent().length()<7*7*32 ){
   token.setErrCode("10");
   return null;
  }
  
  String content=passcard.getConfusedContent();
  int perLen=content.length()/49;
  String str1=content.substring((position1-1)*perLen, position1*perLen);
  String str2=content.substring((position2-1)*perLen, position2*perLen);
  String inputStr1=token.getCard1();
  String inputStr2=token.getCard2();
  if(this.passwordEncoder!=null){
   inputStr1 = md5.getMD5ofStr(md5.getMD5ofStr(inputStr1));
   inputStr2 = md5.getMD5ofStr(md5.getMD5ofStr(inputStr2));
  }
  
  if((!str1.equalsIgnoreCase(inputStr1))||(!str2.equalsIgnoreCase(inputStr2))){
   token.setErrCode("10");
   return null;
  }
  }
  user.setLastIp(token.getIp());
  user.setLastLogin(new Date());
  this.getDao().saveOrUpdate(user);  
  user.setAuthenticated(true);
  
  List userRoles=(List)this.getDao().executeQueryList("UserRole.listRoleByUserID", QueryCmdType.QUERY_NAME, -1, -1, user.getId());
  Set accesses=new HashSet();
  for(UserRole ur:userRoles){
  accesses.add(ur.getRole());  
  }
  user.getOrg().getOrgName();
  if(user.getOrg().getCertTypes()!=null) user.getOrg().getCertTypes().size();//延迟载入一下
  user.setAccesses(accesses);
  return user;
 }
 return null;
 }

重写supports(Class authentication)方法,authentication要


 @Override
 public boolean supports(Class authentication) {
 return authentication.equals(PassCardAuthenticationToken.class);
 }

4.定义filter,实现AbstractAuthenticationProcessingFilter的attemptAuthentication方法,用于获取在登录页面传递过来的参数,spring默认只获取userName(j_username),password(j_username),而且实现UserDetailsService时只传递username

import java.io.IOException;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.util.StringUtils;

import cn.edu.jszg.cert.user.UserLog;
import cn.edu.jszg.cert.user.UserLogService;
import cn.edu.jszg.cert.web.WebApplicationConfiguration;
import cn.edu.jszg.cert.web.controller.portal.auth.RemoteDataValidator;

import com.google.code.kaptcha.servlet.KaptchaServlet;

public class PasscardAuthenticationProcessingFilter extends
 AbstractAuthenticationProcessingFilter {
 private String successPage = "/home/admin/index";
 private String failurePage = "/public/adminLoginEntry";
 private boolean forward = false;
 private boolean useVerifyCode=true;
 private String certLoginUrl;
 
 static Logger logger = Logger.getLogger(PasscardAuthenticationProcessingFilter.class);
 
 private WebApplicationConfiguration config;
 private UserLogService userLogService; 
 
 public void setConfig(WebApplicationConfiguration config) {
 this.config = config;
 }

 
 protected PasscardAuthenticationProcessingFilter() {
 super("/adminLoginCheck");
 }

 public void setUseVerifyCode(boolean useVerifyCode) {
 this.useVerifyCode = useVerifyCode;
 }

 public void setUserLogService(UserLogService userLogService) {
 this.userLogService = userLogService;
 }
 
 public boolean validate(HttpServletRequest request) {
 String userId = request.getParameter("username");
 String md2 = request.getParameter("m");
 String l = request.getParameter("l");
 if (userId == null || md2 == null || l == null) {
  return false;
 }
 long longTime = Long.parseLong(l);
 if (longTime < new Date().getTime()) {
  return false;
 }

 
 try {
  String md1 = RemoteDataValidator.genExamMd5Digest(userId, longTime);
  if (md1.equals(md2))
  return true;
  
 } catch (Exception e) {  
  //e.printStackTrace();
 }
 
 return false;
 }

 
 @Override
 public Authentication attemptAuthentication(HttpServletRequest request,
  HttpServletResponse response) throws AuthenticationException,
  IOException, ServletException {
 
// logger.warn("-----------------start证书登录用户----------");
 HttpSession s = request.getSession(true);
 PassCardAuthenticationToken token = new PassCardAuthenticationToken();
 
 String verifyCode = request.getParameter("verifyCode");
 String userID = request.getParameter("username");
 //....此处省略获取参数,并且验证、赋值的逻辑
 Authentication auth = null;
 
 try {
  //此处调用getAuthenticationManager的authenticate方法,当supports方法返回true时执行authenticate方法
  auth = this.getAuthenticationManager().authenticate(token);
  
  //此处为登录成功后,相应的处理逻辑
  if (auth == null || !auth.isAuthenticated()) {
  s.setAttribute("__login_error", token.getErrCode());
  } else {
  s.removeAttribute("__login_error");
  s.removeAttribute("__login_username");
  s.removeAttribute("__cert_userid");
  if( token.isEnablePasscard()) {
   s.removeAttribute("__passcard_row1");
   s.removeAttribute("__passcard_row2");
   s.removeAttribute("__passcard_column1");
   s.removeAttribute("__passcard_column2");
  }
  }
 } catch (AuthenticationException e) {
  s.setAttribute("__login_error", token.getErrCode());
  throw e;
 }
 
 
 return auth;
 }

 public void setSuccessPage(String successPage) {
 this.successPage = successPage;
 }

 public void setFailurePage(String failurePage) {
 this.failurePage = failurePage;
 }

 public void setForward(boolean forward) {
 this.forward = forward;
 }

 public void setCertLoginUrl(String certLoginUrl) {
 this.certLoginUrl = certLoginUrl;
 }

 @Override
 public void afterPropertiesSet() {
 super.afterPropertiesSet();
 
 AuthenticationResultHandler handler = new AuthenticationResultHandler();
 handler.setForward(forward);
 handler.setLoginFailurePage(failurePage);
 handler.setLoginSuccessPage(successPage);
 handler.setCertLoginUrl(certLoginUrl);
 //设置父类中的处理器
 this.setAuthenticationSuccessHandler(handler);
 this.setAuthenticationFailureHandler(handler);

 }

}

最后为spring-security配置文件中的配置,需要添加authentication-provider的引用,和filter的配置


 
 
 
 
 
  
 
 
 
 
 
 
 
 

还要在http中添加

到此这篇关于详解spring security四种实现方式的文章就介绍到这了,更多相关spring security 实现方式内容请搜索考高分网以前的文章或继续浏览下面的相关文章希望大家以后多多支持考高分网!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/130619.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号