原创

Spring Boot (三)集成spring security


项目GitHub地址 :

https://github.com/FrameReserve/TrainingBoot


Spring Boot (三)集成spring security,标记地址:

https://github.com/FrameReserve/TrainingBoot/releases/tag/0.0.3



pom.xml

只列举 Spring Security配置,完整配置请查看Git项目地址

<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<!--  依赖版本  -->
		<mybatis.version>3.4.1</mybatis.version>
		<mybatis.spring.version>1.3.0</mybatis.spring.version>
		
		<spring-security.version>4.1.0.RELEASE</spring-security.version>
	</properties>



<!-- spring security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring-security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring-security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring-security.version}</version>
        </dependency>


Spring Security 配置类:

src/main/java/com/training/core/security/WebSecurityConfig.java

package com.training.core.security;

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

import javax.annotation.Resource;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.event.LoggerListener;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.training.sysmanager.service.AclResourcesService;
import com.training.sysmanager.service.impl.AclResourcesServiceImpl;

/**
 * Created by Athos on 2016-10-16.
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Resource
	private UserDetailsService userDetailsService;

	@Resource
	private MySecurityMetadataSource mySecurityMetadataSource;

	@Override
	protected void configure(HttpSecurity http) throws Exception {

		http.addFilterAfter(MyUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
		// 开启默认登录页面
		http.authorizeRequests().anyRequest().authenticated().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
			public <O extends FilterSecurityInterceptor> O postProcess(O fsi) {
				fsi.setSecurityMetadataSource(mySecurityMetadataSource);
				fsi.setAccessDecisionManager(accessDecisionManager());
				fsi.setAuthenticationManager(authenticationManagerBean());
				return fsi;
			}
		}).and().exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login.html")).and().logout().logoutSuccessUrl("/index.html").permitAll();
		// 自定义accessDecisionManager访问控制器,并开启表达式语言
		http.exceptionHandling().accessDeniedHandler(accessDeniedHandler()).and().authorizeRequests().anyRequest().authenticated().expressionHandler(webSecurityExpressionHandler());

		// 自定义登录页面
		http.csrf().disable();

		// 自定义注销
		// http.logout().logoutUrl("/logout").logoutSuccessUrl("/login")
		// .invalidateHttpSession(true);

		// session管理
		http.sessionManagement().maximumSessions(1);

		// RemeberMe
		// http.rememberMe().key("webmvc#FD637E6D9C0F1A5A67082AF56CE32485");

	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		// 自定义UserDetailsService
		auth.userDetailsService(userDetailsService);
	}

	@Bean
	UsernamePasswordAuthenticationFilter MyUsernamePasswordAuthenticationFilter() {
		UsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter();
		myUsernamePasswordAuthenticationFilter.setPostOnly(true);
		myUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
		myUsernamePasswordAuthenticationFilter.setUsernameParameter("name_key");
		myUsernamePasswordAuthenticationFilter.setPasswordParameter("pwd_key");
		myUsernamePasswordAuthenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
		myUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(simpleUrlAuthenticationFailureHandler());
		return myUsernamePasswordAuthenticationFilter;
	}

	@Bean
	AccessDeniedHandler accessDeniedHandler() {
		AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
		accessDeniedHandler.setErrorPage("/securityException/accessDenied");
		return accessDeniedHandler;
	}

	@Bean
	public LoggerListener loggerListener() {
		System.out.println("org.springframework.security.authentication.event.LoggerListener");
		return new LoggerListener();
	}

	@Bean
	public org.springframework.security.access.event.LoggerListener eventLoggerListener() {
		System.out.println("org.springframework.security.access.event.LoggerListener");
		return new org.springframework.security.access.event.LoggerListener();
	}

	/*
	 * 
	 * 这里可以增加自定义的投票器
	 */
	@Bean(name = "accessDecisionManager")
	public AccessDecisionManager accessDecisionManager() {
		List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList();
		decisionVoters.add(new RoleVoter());
		decisionVoters.add(new AuthenticatedVoter());
		decisionVoters.add(webExpressionVoter());// 启用表达式投票器
		MyAccessDecisionManager accessDecisionManager = new MyAccessDecisionManager(decisionVoters);
		return accessDecisionManager;
	}

	@Bean(name = "authenticationManager")
	@Override
	public AuthenticationManager authenticationManagerBean() {
		AuthenticationManager authenticationManager = null;
		try {
			authenticationManager = super.authenticationManagerBean();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return authenticationManager;
	}

	@Bean(name = "failureHandler")
	public SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler() {
		return new SimpleUrlAuthenticationFailureHandler("/getLoginError");
	}

	@Bean(name = "aclResourcesService")
	@ConditionalOnMissingBean
	public AclResourcesService aclResourcesService() {
		return new AclResourcesServiceImpl();
	}

	/*
	 * 表达式控制器
	 */
	@Bean(name = "expressionHandler")
	public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
		DefaultWebSecurityExpressionHandler webSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
		return webSecurityExpressionHandler;
	}

	/*
	 * 表达式投票器
	 */
	@Bean(name = "expressionVoter")
	public WebExpressionVoter webExpressionVoter() {
		WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
		webExpressionVoter.setExpressionHandler(webSecurityExpressionHandler());
		return webExpressionVoter;
	}

}


自定义 UserDetailsService 用户、角色、资源获取类:

src/main/java/com/training/core/security/UserDetailsServiceImpl.java

package com.training.core.security;

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

import javax.annotation.Resource;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.training.sysmanager.entity.AclResources;
import com.training.sysmanager.entity.AclUser;
import com.training.sysmanager.service.AclResourcesService;
import com.training.sysmanager.service.AclRoleResourcesService;
import com.training.sysmanager.service.AclUserService;

/**
 * Created by Athos on 2016-10-16.
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl  implements UserDetailsService {
    
	@Resource
    private AclUserService aclUserService;
    @Resource
    private AclRoleResourcesService aclRoleResourcesService;
    @Resource
    private AclResourcesService aclResourcesService;

    /* (non-Javadoc)
     * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
        AclUser aclUser = aclUserService.findAclUserByName(username);
        String resourceIds = aclRoleResourcesService.selectResourceIdsByRoleIds(aclUser.getRoleIds());
        List<AclResources> aclResourcesList = aclResourcesService.selectAclResourcesByResourceIds(resourceIds);
        for (AclResources aclResources : aclResourcesList) {
        	auths.add(new SimpleGrantedAuthority(aclResources.getAuthority().toUpperCase()));
		}
//        auths.addAll(aclResourcesList.stream().map(resources -> new SimpleGrantedAuthority(resources.getAuthority().toUpperCase())).collect(Collectors.toList()));
        return new User(aclUser.getUserName().toLowerCase(),aclUser.getUserPwd().toLowerCase(),true,true,true,true,auths);
    }
}


自定义securityMetadataSource:

src/main/java/com/training/core/security/MySecurityMetadataSource.java

package com.training.core.security;

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

import javax.servlet.http.HttpServletRequest;

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.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;

import com.training.sysmanager.entity.AclResources;
import com.training.sysmanager.service.AclResourcesService;

/**
 * Created by Athos on 2016-10-16.
 */
@Component("mySecurityMetadataSource")
public class MySecurityMetadataSource  implements FilterInvocationSecurityMetadataSource {

    private static Map<String,Collection<ConfigAttribute>> aclResourceMap = null;
    private AclResourcesService aclResourcesService;

    /**
     * 构造方法
     */
    //1
    public MySecurityMetadataSource(AclResourcesService aclResourcesService){
        this.aclResourcesService=aclResourcesService;
        loadResourceDefine();
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object)throws IllegalArgumentException{
        HttpServletRequest request=((FilterInvocation)object).getRequest();
        Iterator<String> ite = aclResourceMap.keySet().iterator();
        while (ite.hasNext()){
            String resURL = ite.next();
            RequestMatcher requestMatcher = new AntPathRequestMatcher(resURL);
            if(requestMatcher.matches(request)){
                return aclResourceMap.get(resURL);
            }
        }
        return null;
    }
    //4
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        System.out.println("metadata : getAllConfigAttributes");
        return null;
    }
    //3
    @Override
    public boolean supports(Class<?> clazz) {
        System.out.println("metadata : supports");
        return true;
    }


    private void loadResourceDefine(){
        /**
         * 因为只有权限控制的资源才需要被拦截验证,所以只加载有权限控制的资源
         */
        List<AclResources> aclResourceses = aclResourcesService.selectAclResourcesTypeOfRequest();
        aclResourceMap = new HashMap<>();
        for (AclResources aclResources:aclResourceses){
            ConfigAttribute ca = new SecurityConfig(aclResources.getAuthority().toUpperCase());
            String url = aclResources.getUrl();
            if(aclResourceMap.containsKey(url)){
                Collection<ConfigAttribute> value = aclResourceMap.get(url);
                value.add(ca);
                aclResourceMap.put(url,value);

            }else {
                Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
                atts.add(ca);
                aclResourceMap.put(url,atts);
            }
        }
    }
}


自定义AbstractAccessDecisionManager权限决策类,

src/main/java/com/training/core/security/MyAccessDecisionManager.java

package com.training.core.security;

import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.vote.AbstractAccessDecisionManager;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

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

/**
 * Created by Athos on 2016-10-16.
 */

public class MyAccessDecisionManager  extends AbstractAccessDecisionManager {
    protected MyAccessDecisionManager(List<AccessDecisionVoter<? extends Object>> decisionVoters) {
        super(decisionVoters);
    }

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        if(configAttributes==null){
            return;
        }
        Iterator<ConfigAttribute> ite = configAttributes.iterator();
        while(ite.hasNext()){
            ConfigAttribute ca = ite.next();
            String needRole = (ca).getAttribute();
            for (GrantedAuthority ga : authentication.getAuthorities()){
                if (needRole.equals(ga.getAuthority())){
                    return;
                }
            }
        }
        throw new AccessDeniedException("没有权限,拒绝访问!");
    }
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return false;
    }

    /**
     * Iterates through all <code>AccessDecisionVoter</code>s and ensures each can support
     * the presented class.
     * <p>
     * If one or more voters cannot support the presented class, <code>false</code> is
     * returned.
     *
     * @param clazz the type of secured object being presented
     * @return true if this type is supported
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}


用户、角色、资源(菜单)略。

详情请看GIT完成工程。

https://github.com/FrameReserve/TrainingBoot














































































正文到此结束
Loading...