详解spring security四种实现方式

网友投稿 703 2023-03-15

详解spring security四种实现方式

详解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

xmlns:security="http://springframework.org/schema/security"

xmlns:p="http://springframework.org/schema/p" xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans-4.0.xsd

http://springframework.org/schema/security

http://springframework.org/schema/security/spring-security-4.0.xsd">

authorities="ROLE_USER" />

xmlns:security="http://springframework.org/schema/security"

xmlns:p="http://springframework.org/schema/p" xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans-4.0.xsd

http://springframework.org/schema/security

http://springframework.org/schema/security/spring-security-4.0.xsd">

authorities="ROLE_USER" />

authorities="ROLE_USER" />

2.实现UserDetailsService

先整理下spring secruity验证流程:

springSecurity的登录验证是由org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter这个过滤器来完成的,在该类的父类AbstractAuthenticationProcessingFilter中有一个AuthenticationManager接口属性,验证工作主要是通过这个AuthenticationManager接口的实例来完成的。在默认情况下,springSecurity框架会把org.springframework.security.authentication.ProviderManager类的实例注入到该属性

UsernamePasswordAuthenticationFilter的验证过程如下:

1. 首先过滤器会调用自身的attemptAuthentication方法,从request中取出authentication, authentication是在org.springframework.security.web.context.SecurityContextPersistenceFilter过滤器中通过捕获用户提交的登录表单中的内容生成的一个org.springframework.security.core.Authentication接口实例.

2. 拿到authentication对象后,过滤器会调用ProviderManager类的authenticate方法,并传入该对象

3.ProviderManager类的authenticate方法中会调用类中的List providers集合中的各个AuthenticationProvider接口实现类中的authenticate(Authentication authentication)方法进行验证,由此可见,真正的验证逻辑是由各个AuthenticationProvider接口实现类来完成的。DaoAuthenticationProvider类是默认情况下注入的一个AuthenticationProvider接口实现类

4.provider的实现类在验证用户时,会调用userDetailsService的实现类的loadUserByUsername方法来获取用户信息,

首先spring-security配置文件

xmlns:beans="http://springframework.org/schema/beans"

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans-4.3.xsd

http://springframework.org/schema/security

http://springframework.org/schema/security/spring-security.xsd">

xmlns:beans="http://springframework.org/schema/beans"

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans-4.3.xsd

http://springframework.org/schema/security

http://springframework.org/schema/security/spring-security.xsd">

userDetailsService实现:

/**

*

*/

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

import java.util.ArrayList;

import java.util.HashMap;

import java.util.HashSet;

import java.util.List;

import java.util.Map;

import java.util.Set;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.dao.DataAccessException;

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.security.core.userdetails.UserDetailsService;

import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.ultrapower.me.util.Constants;

import com.ultrapower.me.util.dbDao.SpringBeanUtil;

import com.ultrapower.me.util.security.SecurityManager;

import com.ultrapower.me.util.security.entity.Resource;

import com.ultrapower.me.util.security.entity.Role;

import com.ultrapower.me.util.security.entity.User;

import com.ultrapower.me.util.task.PasswordUtils;

public class SecurityManagerSupport implements UserDetailsService{

private Log log = LogFactory.getLog(this.getClass().getName());

public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {

// List users = getHibernateTemplate().find("FROM User user WHERE user.name = ? AND user.disabled = false", userName);

log.info("SecurityManagerSupport.loadUserByUsername.userName:"+userName);

User user =null;

if("admin".equals(userName)){

Set 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;

/**

* The default constructor

*/

public User() {

}

/**

* Returns the authorites string

*

* eg.

* downpour --- ROLE_ADMIN,ROLE_USER

* robbin --- ROLE_ADMIN

*

* @return

*/

public String getAuthoritiesString() {

List authorities = new ArrayList();

for(GrantedAuthority authority : this.getAuthorities()) {

authorities.add(authority.getAuthority());

}

return StringUtils.join(authorities, ",");

}

@Override

public Collection extends GrantedAuthority> 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;

}

/*

*帐号是否不过期,false则验证不通过

*/

public boolean isAccountNonExpired() {

return true;

}

/*

* 帐号是否不锁定,false则验证不通过

*/

public boolean isAccountNonLocked() {

return true;

}

/*

* 凭证是否不过期,false则验证不通过

*/

public boolean isCredentialsNonExpired() {

return true;

}

/*

* 该帐号是否启用,false则验证不通过

*/

public boolean isEnabled() {

return !disabled;

}

/**

* @return the name

*/

public String getName() {

return name;

}

/**

* @return the disabled

*/

public boolean isDisabled() {

return disabled;

}

/**

* @return the roles

*/

public Set getRoles() {

return roles;

}

/**

* @return the roleResources

*/

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;

}

/**

* @param name the name to set

*/

public void setName(String name) {

this.name = name;

}

/**

* @param password the password to set

*/

public void setPassword(String password) {

this.password = password;

}

/**

* @param disabled the disabled to set

*/

public void setDisabled(boolean disabled) {

this.disabled = disabled;

}

/**

* @param roles the roles to set

*/

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>();

/*

* 初始化用户权限,为了简便操作没有从数据库获取

* 实际操作可以从数据库中获取所有资源路径url所对应的权限

*/

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-/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;

}

/* (non-Javadoc)

* @see org.springframework.security.intercept.ObjectDefinitionSource#getConfigAttributeDefinitions()

*/

@SuppressWarnings("rawtypes")

public Collection getConfigAttributeDefinitions() {

return null;

}

/* (non-Javadoc)

* @see org.springframework.security.intercept.ObjectDefinitionSource#supports(java.lang.Class)

*/

public boolean supports(@SuppressWarnings("rawtypes") Class clazz) {

return true;

}

/**

*

* @param filterInvocation

* @return

*/

@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 {

/**

* 检查用户是否够权限访问资源

* authentication 是从spring的全局缓存SecurityContextHolder中拿到的,里面是用户的权限信息

* object 是url

* configAttributes 所需的权限

* @see org.springframework.security.access.AccessDecisionManager#decide(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection)

*/

@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;

}

/**

* 当事人,登录名 用户Id

*/

@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;

/*

* 这里进行逻辑认证操作,可以获取token中的属性来自定义验证逻辑,代码验证逻辑可以不用管

* 如果使用UserDetailsService的实现类来验证,就只能获取userName,不够灵活

*/

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.gethttp://MD5ofStr(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);

/*

* 导入一次角色权限,并且把权限set到User中,用于spring验证用户权限(getAuthorities方法)

*/

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 extends Object> authentication)方法,authentication要

/**

* 如果此处验证不通过,是不会执行authentication方法的

*/

@Override

public boolean supports(Class extends Object> 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;

}

/**

* 实现AbstractAuthenticationProcessingFilter的有参构造

* 没记错的话,相当于该filter的访问路径

*/

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;

}

/**

* 可以通过request获取页面传递过来的参数,并且set到相应的token中

*/

@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();

/*

*该处理器实现了AuthenticationSuccessHandler, AuthenticationFailureHandler

*用于处理登录成功或者失败后,跳转的界面

*/

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中添加

ConfigAttribute cano = new SecurityConfig("ROLE_NO");

attsno.add(cano);

map.put("/http://blog.csdn-/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;

}

/* (non-Javadoc)

* @see org.springframework.security.intercept.ObjectDefinitionSource#getConfigAttributeDefinitions()

*/

@SuppressWarnings("rawtypes")

public Collection getConfigAttributeDefinitions() {

return null;

}

/* (non-Javadoc)

* @see org.springframework.security.intercept.ObjectDefinitionSource#supports(java.lang.Class)

*/

public boolean supports(@SuppressWarnings("rawtypes") Class clazz) {

return true;

}

/**

*

* @param filterInvocation

* @return

*/

@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 {

/**

* 检查用户是否够权限访问资源

* authentication 是从spring的全局缓存SecurityContextHolder中拿到的,里面是用户的权限信息

* object 是url

* configAttributes 所需的权限

* @see org.springframework.security.access.AccessDecisionManager#decide(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection)

*/

@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;

}

/**

* 当事人,登录名 用户Id

*/

@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;

/*

* 这里进行逻辑认证操作,可以获取token中的属性来自定义验证逻辑,代码验证逻辑可以不用管

* 如果使用UserDetailsService的实现类来验证,就只能获取userName,不够灵活

*/

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.gethttp://MD5ofStr(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);

/*

* 导入一次角色权限,并且把权限set到User中,用于spring验证用户权限(getAuthorities方法)

*/

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 extends Object> authentication)方法,authentication要

/**

* 如果此处验证不通过,是不会执行authentication方法的

*/

@Override

public boolean supports(Class extends Object> 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;

}

/**

* 实现AbstractAuthenticationProcessingFilter的有参构造

* 没记错的话,相当于该filter的访问路径

*/

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;

}

/**

* 可以通过request获取页面传递过来的参数,并且set到相应的token中

*/

@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();

/*

*该处理器实现了AuthenticationSuccessHandler, AuthenticationFailureHandler

*用于处理登录成功或者失败后,跳转的界面

*/

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中添加

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:小程序中怎么使用插件(小程序中怎么使用插件打开)
下一篇:app系统软件开发(系统app软件开发平台搭建)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~