• spring security 3.2 配置详解(结合数据库)


    没事就来了解下spring security.网上找了很多资料。有过时的,也有不是很全面的。各种问题也算是让我碰了个遍。这样吧。我先把整个流程写下来,之后在各个易混点分析吧。

    1.建立几个必要的页面。

    login.jsp   index.jsp    user.jsp     admin.jsp    error.jsp 后面几个只是用来做跳转的,里面没什么要注意的,就贴出login里面的吧

    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>login</title>
    </head>
    <body>
        <form action="/mavenTest/j_spring_security_check" method="post">
            账户:<input type="text" name="j_username" id="username"/>
            密码:<input type="text" name="j_password" id="password"/>
            <input type="submit" value="登陆"/>
        </form>
    </body>
    </html>

    2.配置web.xml  没有用的就没有粘贴了

    <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

    3.忘记吧pom.xml文件给出来了  版本为<org.springframework-version>3.2.3.RELEASE</org.springframework-version>

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

    4.配置spring security .xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
        xmlns:beans="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
               http://www.springframework.org/schema/security
               http://www.springframework.org/schema/security/spring-security.xsd">
         
         <!-- 不需要进行安全认证的资源 -->
        <http pattern="/resources/**" security="none" />
        <http pattern="/login.jsp" security="none"/>
        
        <!-- 资源所需要的权限 -->
        <http auto-config='true'>
            <form-login login-page="/login.jsp" 
                default-target-url="/index.jsp"
                authentication-failure-url="/login.jsp?error=true" />
            <logout logout-success-url="/index.jsp"/>
            
            <!-- 尝试访问没有权限的页面时跳转的页面 -->
            <access-denied-handler error-page="/error-noauth.jsp"/>
            
            <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
        </http>
        
        <!-- 自定义一个filter,必须包含authenticationManager,accessDecisionManager,
        securityMetadataSource三个属性 所有的功能都在这三个类中实现-->
        
        <beans:bean id="myFilter" class="com.demo.im.model.security.MyFilterSecurotyInterceptor">
            <beans:property name="authenticationManager" 
            ref="authenticationManager" />
            <beans:property name="accessDecisionManager" 
            ref ="myAccessDecisionManagerBean"/>
            <beans:property name="securityMetadataSource" 
            ref="securityMetadaSource"/>
        </beans:bean>
        
        <!-- 认证管理器,实现用户认证的入口,主要实现userdetailsservice -->
        <authentication-manager alias="authenticationManager">
            <authentication-provider
                user-service-ref="myUserDetailService">
            </authentication-provider>
        </authentication-manager>
        
        <beans:bean id="myUserDetailService"
            class="com.demo.im.model.security.DefaultUserDetailsService">
        </beans:bean>
        
        <!-- 访问决策,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
        <beans:bean id="myAccessDecisionManagerBean"
            class="com.demo.im.model.security.MyAccessDecisionManager" />
        
        <beans:bean id="securityMetadaSource" 
            class="com.demo.im.model.security.MyInvocationSecurityMetadaSource"/>
        
    </beans:beans>

    5.MyFilterSecurotyInterceptor   自定义filter的代码如下。

    其中最核心的代码是  invoke() 方法中的  

    InterceptorStatusToken token = super.beforeInvocation(fi);
    这一句在dofilter之前进行权限验证,而具体的实现交给了accessDecisionManager,下面将继续讨论

    package com.demo.im.model.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 MyFilterSecurotyInterceptor extends AbstractSecurityInterceptor implements Filter {
    
        private FilterInvocationSecurityMetadataSource securityMetadataSource;
        
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
    
            FilterInvocation fi = new FilterInvocation(request, response,chain);
            invoke(fi);
        }
    
        @Override
        public void destroy() {
            // 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;
        }
    
        public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
            return securityMetadataSource;
        }
    
        public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
            this.securityMetadataSource = securityMetadataSource;
        }
    
        public void invoke(FilterInvocation fi) throws IOException
            ,ServletException{
            
            InterceptorStatusToken token = super.beforeInvocation(fi);
            try {
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
            } catch (Exception e) {
                // TODO: handle exception
            }finally{
                super.afterInvocation(token, null);
            }
        }
    }

    6.DefaultUserDetailsService的实现

    在这个类中你可以通过读取数据库来进行权限赋值,下面的代码未注解的是我写的静态的

    package com.demo.im.model.security;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.GrantedAuthorityImpl;
    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.demo.im.entity.Role;
    import com.demo.im.entity.TUser;
    import com.demo.im.model.dao.TUserMapper;
    @Service
    public class DefaultUserDetailsService implements UserDetailsService {
        @Autowired
        TUserMapper userDao;
        
        @Override
        public UserDetails loadUserByUsername(String username)
                throws UsernameNotFoundException {
            // TODO Auto-generated method stub
            System.out.println("userDetail********");
            Collection <GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
            
            GrantedAuthority auth2 = new GrantedAuthorityImpl("ROLE_ADMIN");
            
            auths.add(auth2);
            
            User user = new User(username,"1111",true,true,true,true,auths);
            return user;
            
            
    //        TUser paramU = new TUser();
    //        paramU.setUsername(username);
    //        List<TUser> userList = userDao.selectByUserParam(paramU);
    //        TUser user = new TUser();
    //        if(userList==null || userList.size()<=0){
    //            throw new UsernameNotFoundException("username");
    //        }
    //        //得到用户权限
    //        if(user.getRoles()!=null && user.getRoles().size()>0){
    //            
    //            for(Role role : user.getRoles()){
    //                GrantedAuthority grantedAuthority = new GrantedAuthorityImpl(
    //                        role.getRolecode().toUpperCase());
    //                auths.add(grantedAuthority);
    //            }
    //            
    //        }
    //        user.setAuthorities(auths);
    //        return user;
        }
    
    }

    7.MyInvocationSecurityMetadaSource类的内容

    这个类说白了就是从数据库中取出资源对应的权限,我这里也是写的静态的,修改为动态的方法也很简单,执行一个查询就行了

    package com.demo.im.model.security;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    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;
    
    public class MyInvocationSecurityMetadaSource 
        implements FilterInvocationSecurityMetadataSource{
    
    //    private UrlMatcher urlMatcher = new AntUrlPathMatcher();
        private static Map<String,Collection<ConfigAttribute>> resourceMap = null;
        
        public MyInvocationSecurityMetadaSource(){
            loadResourceDefine();
        }
        
        private void loadResourceDefine(){
            resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
            Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
            
            ConfigAttribute ca = new SecurityConfig("ROLE_ADMIN");
            
            atts.add(ca);
            resourceMap.put("/user.jsp", atts);
            resourceMap.put("/admin.jsp", atts);
            resourceMap.put("/index.jsp",atts);
            
        }
        
        @Override
        public Collection<ConfigAttribute> getAttributes(Object object)
                throws IllegalArgumentException {
            // TODO Auto-generated method stub
            String url = ((FilterInvocation)object).getRequestUrl();
            Iterator<String> ite = resourceMap.keySet().iterator();
            
            while(ite.hasNext()){
                String resURL = ite.next();
                
                if(url.equalsIgnoreCase(resURL)){
                    return resourceMap.get(resURL);
                }
                
            }
            
            return null;
        }
    
        @Override
        public Collection<ConfigAttribute> getAllConfigAttributes() {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public boolean supports(Class<?> clazz) {
            // TODO Auto-generated method stub
            return true;
        }
    
    }

    8.最后就是决策类了MyAccessDecisionManager

    这个类就更好理解了,我们知道了用户的角色,我们也知道资源的角色,对比一下,也就是decide()一致就返回,不行就抛异常

    package com.demo.im.model.security;
    
    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 MyAccessDecisionManager implements AccessDecisionManager{
    
        @Override
        public void decide(Authentication authentication, Object object,
                Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,
                InsufficientAuthenticationException {
            if(configAttributes  == null){
                return ;
            }
            System.out.println(object.toString());
            Iterator<ConfigAttribute> ite = configAttributes.iterator();
            while(ite.hasNext()){
                ConfigAttribute ca = ite.next();
                String needRole = ((SecurityConfig)ca).getAttribute();
                
                for(GrantedAuthority ga : authentication.getAuthorities()){
                    if(needRole.equals(ga.getAuthority())){
                        return ;
                    }
                }
            }
            throw new AccessDeniedException("no right");
            
        }
    
        @Override
        public boolean supports(ConfigAttribute arg0) {
            // TODO Auto-generated method stub
            return true;
        }
    
        @Override
        public boolean supports(Class<?> arg0) {
            // TODO Auto-generated method stub
            return true;
        }
    
    }

    9总结:

    到这里一个基本的spring  security算是搭建完了。过会在来说说我遇到的坑。方便以后大家找自己的坑。

  • 相关阅读:
    python 高阶函数
    python 列表
    python 模块
    浅谈HashMap原理,记录entrySet中的一些疑问
    extjs Tree中避免连续单击会连续请求服务器
    Java类的加载顺序
    mybatis中集成sharing-jdbc采坑
    tomcat采坑
    AQS原理
    Redis分布式锁原理
  • 原文地址:https://www.cnblogs.com/wangxiangstudy/p/5961118.html
Copyright © 2020-2023  润新知