spring boot 中spring security使用数据库保存权限

WebSecurityConfig

package com.maven;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.maven.security.MyFilterSecurityInterceptor;


@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private DataSource dataSource;

    @Autowired
    @Qualifier("myUserDetailsService")
    private UserDetailsService userDetailsService;

    @Autowired
    @Qualifier("myAccessDecisionManager")
    private AccessDecisionManager accessDecisionManager;

    @Autowired
    @Qualifier("mySecurityMetadataSource")
    private FilterInvocationSecurityMetadataSource securityMetadataSource;

    @Autowired
    private AuthenticationManagerBuilder authenticationManagerBuilder;

    private AuthenticationManager authenticationManager;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http 
        //自定义过滤器,把资源配置存放到数据库中
        .addFilterBefore(filter(),FilterSecurityInterceptor.class)
            .exceptionHandling()
            .and()
        .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/home")
            .and()
        .logout()
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
            .logoutSuccessUrl("/login?logout")
            .invalidateHttpSession(true)
            .deleteCookies("remember-me")
            .and()
        .rememberMe()
            .tokenRepository(tokenRepository())
            .tokenValiditySeconds(1209600)//默认2.rememberMeCookieName("remember-me")
            .userDetailsService(userDetailsService)
            .rememberMeParameter("remember-me");
    }

    private PersistentTokenRepository tokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }

    // 配置AuthenticationManager
    @Bean
    public AuthenticationManager authenticationManagerBean() {
        authenticationManagerBuilder.authenticationProvider(authenticationProvider());
        return authenticationManagerBuilder.getOrBuild();
    }

    // 获取AuthenticationManager,避免多次调用authenticationManagerBean()
    public AuthenticationManager getAuthenticationManager() {
        if (this.authenticationManager == null) {
            return authenticationManagerBean();
        } else {
            return this.authenticationManager;
        }
    }

    // 自定义JpaFilterSecurityInterceptor过滤器
    public MyFilterSecurityInterceptor filter() throws Exception {
        MyFilterSecurityInterceptor filter = new MyFilterSecurityInterceptor();
        // 认证管理器,实现用户认证的入口
        filter.setAuthenticationManager(getAuthenticationManager());
        // 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源
        filter.setAccessDecisionManager(accessDecisionManager);
        // 资源源数据定义,即定义某一资源可以被哪些角色访问
        filter.setSecurityMetadataSource(securityMetadataSource);
        return filter;
    }

    // 配置DaoAuthenticationProvider
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        // 设置不隐藏UserNotFoundExceptions
        authenticationProvider.setHideUserNotFoundExceptions(false);
        // 设置自定义UserDetailsService
        authenticationProvider.setUserDetailsService(userDetailsService);
        // 设置密码加密方式
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        authenticationProvider.setPasswordEncoder(passwordEncoder);
        return authenticationProvider;
    }

}

MyAccessDecisionManager

/**
 * copyright by liukai
 */
package com.maven.security;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
import org.springframework.stereotype.Service;

@Service("myAccessDecisionManager")
public class MyAccessDecisionManager implements AccessDecisionManager{

    private final static Logger logger = LoggerFactory.getLogger(MyAccessDecisionManager.class);

    /* (non-Javadoc)
     * @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<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {     
        if (configAttributes == null) {
            return; //如果访问资源不需要任何权限则直接通过  
        }
        //所请求的资源拥有的权限(一个资源对多个权限)
        Iterator<ConfigAttribute> ite = configAttributes.iterator();
        while (ite.hasNext()) {
            ConfigAttribute ca = ite.next();
            String needRole = ((SecurityConfig) ca).getAttribute();
            // ga 为用户所被赋予的权限。 needRole 为访问相应的资源应该具有的权限。
            for (GrantedAuthority ga : authentication.getAuthorities()) {
                logger.info("该资源所需要的权限是:"+needRole +",当前用户的权限是:"+ ga.getAuthority());
                if (needRole.trim().equals(ga.getAuthority().trim())) {
                    return;
                }
            }
        }
        logger.info("权限不足,无法访问!");
        throw new AccessDeniedException("不允许访问!");
    }

    /* (non-Javadoc)
     * @see org.springframework.security.access.AccessDecisionManager#supports(org.springframework.security.access.ConfigAttribute)
     */
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    /* (non-Javadoc)
     * @see org.springframework.security.access.AccessDecisionManager#supports(java.lang.Class)
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

}

MyFilterSecurityInterceptor

/**
 * copyright by liukai
 */
package com.maven.security;

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 MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter{

    private FilterInvocationSecurityMetadataSource securityMetadataSource;

    /**
     * @return the securityMetadataSource
     */
    public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
        return securityMetadataSource;
    }

    /**
     * @param securityMetadataSource the securityMetadataSource to set
     */
    public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
        this.securityMetadataSource = securityMetadataSource;
    }

    /* (non-Javadoc)
     * @see org.springframework.security.access.intercept.AbstractSecurityInterceptor#getSecureObjectClass()
     */
    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    /* (non-Javadoc)
     * @see org.springframework.security.access.intercept.AbstractSecurityInterceptor#obtainSecurityMetadataSource()
     */
    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return securityMetadataSource;
    }

    /* (non-Javadoc)
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    /* (non-Javadoc)
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
         FilterInvocation fi = new FilterInvocation(request, response, chain);
         invoke(fi);
    }

    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }

    /* (non-Javadoc)
     * @see javax.servlet.Filter#destroy()
     */
    @Override
    public void destroy() {

    }

}

MySecurityMetadataSource

/**
 * copyright by liukai
 */
package com.maven.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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.stereotype.Service;
import org.springframework.util.AntPathMatcher;

import com.maven.auth.service.AuthService;

@Service("mySecurityMetadataSource")
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource{

    private final static Logger logger = LoggerFactory.getLogger(MySecurityMetadataSource.class);

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

     public MySecurityMetadataSource(AuthService authService) {
        //查询所有资源路径和角色
        List<Map<String,Object>> resourceRoles = authService.findAllResourceAndRole();
        //根据URL组装权限Map key为URL,集合为权限集合
        resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
        for(Map<String,Object> resourceRole :resourceRoles) {
            ConfigAttribute ca = new SecurityConfig((String) resourceRole.get("CODE"));
            String url = (String) resourceRole.get("PATH");
            if (resourceMap.containsKey(url)) {
                Collection<ConfigAttribute> value = resourceMap.get(url);
                value.add(ca);
                resourceMap.put(url, value);
            } else {
                Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
                atts.add(ca);
                resourceMap.put(url, atts);
            }
        }
     }

    /* (non-Javadoc)
     * @see org.springframework.security.access.SecurityMetadataSource#getAttributes(java.lang.Object)
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        // object 是一个URL,被用户请求的url。
        String url = ((FilterInvocation) object).getRequestUrl();

        int firstQuestionMarkIndex = url.indexOf("?");
        if (firstQuestionMarkIndex != -1) {
            url = url.substring(0, firstQuestionMarkIndex);
        }
        Iterator<String> ite = resourceMap.keySet().iterator();
        AntPathMatcher matcher = new AntPathMatcher();
        matcher.setTrimTokens(false);
        while (ite.hasNext()) {
            String resURL = ite.next();
            if (matcher.match(resURL, url)) {
                logger.info("资源配置URL为"+resURL+"请求的URL为:"+url);
                return resourceMap.get(resURL);
            }
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.springframework.security.access.SecurityMetadataSource#getAllConfigAttributes()
     */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        // TODO Auto-generated method stub
        return null;
    }

    /* (non-Javadoc)
     * @see org.springframework.security.access.SecurityMetadataSource#supports(java.lang.Class)
     */
    @Override
    public boolean supports(Class<?> clazz) {
        // TODO Auto-generated method stub
        return true;
    }

}

MyUserDetailsService


package com.maven.security;

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

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.maven.auth.dao.UserDao;
import com.maven.auth.entity.Role;
import com.maven.auth.entity.User;

@Transactional
@Service("myUserDetailsService")
public class MyUserDetailsService implements UserDetailsService{

    @Autowired
    private UserDao userDao;

    /* (non-Javadoc)
     * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = this.userDao.findByUsername(username);
        if(user==null) {
            throw new UsernameNotFoundException("用户"+username+"不存在!");
        }
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        List<Role> roles = user.getRoles();
        for(Role role:roles) {
            authorities.add(new SimpleGrantedAuthority(role.getCode()));
        }
        UserDetails userDetails = new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),authorities);
        return userDetails;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值