集成SSH和SpringSecurity

Posted z8z87878

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了集成SSH和SpringSecurity相关的知识,希望对你有一定的参考价值。

呃,工作并不是我想的那么好找,去深圳二十天,面试了六家,第一天三家把我累吐血,在外面坐车转地铁走路六个多小时,三家面试加起来没超过15分钟,一家培训机构,一家说我没工作经验,HR拿我凑人数,一家给两千在深圳….第四家我没把握好,第五家等了三个小时九个人群面…第六家尼玛把我气回来了。面试质量太差了。怪我不会写简历,第四家没把握好,没在深圳坚持下来吧。找工作真不简单.南昌校招没几家公司,过段时间可能会去杭州,唉。乘着这一个月学习了下javaee的那些常见框架,以后也可以找android和java后台的工作

转载请声明出处:由http://blog.csdn.net/z8z87878转载

这里就不讲导包了,那么多…..缺包报错也能找,其中Structs2它是集成Spring的,为什么这么说呢,因为它有一个Structs2-Spring-puling插件jar包,所以Spring文件中不用配它,就是要注意Structs2引用的class不是单例的,是原型,所以需要把控制类标记为原型的。好的,开始配置吧。先配置web.xml文件


    <!-- Spring的监听器,监听服务的生命周期来管理bean -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:ApplicationContext*.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- SpringSecurity相关,需要配置在Structs2的拦截器前面,由它来负责登陆权限控制 -->
    <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>


    <!-- Structs2相关,配置核心拦截器 -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <!-- 默认不拦截转发,这里修改成拦截,为后面集成SpringSecurity -->
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

然后再classpath下即src下创建ApplicationContext.xml配置文件,因为我们要再里面集成Hibernate,所以我们先完成Hibernate的自身配置。在src下创建db.properties配置连接数据库的属性

jdbc.user=root(账号)
jdbc.password=123456(密码)
jdbc.driverClass=com.mysql.jdbc.Driver(数据库对应的驱动)
jdbc.jdbcUrl=jdbc:mysql:///dbName(///后的是数据库名)

然后再在src下创建hibernate.cfg.xml配置常规属性(建议装Hibernate和Spring的插件,就不用自己找dtd和Schme依赖了)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>


        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property><!-- 方言 -->
        <property name="hibernate.hbm2ddl.auto">update</property> <!-- 表的生成策略 -->
        <property name="hibernate.show_sql">true</property>      <!-- 控制台打印SQL -->
        <property name="hibernate.format_sql">true</property>   

        <!-- 二级缓存相关 -->
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
        <property name="hibernate.cache.use_query_cache">true</property>

    </session-factory>
</hibernate-configuration>

好,Hibernate的准备工作就这样做好了,来进入Spring的配置文件ApplicationContext.xml吧

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <!-- 自动扫描包 -->
    <context:component-scan base-package="com.ee.ems"></context:component-scan>

    <!-- 文件中要用到刚才配置的连接数据库信息,这里把它导进来,分开配置好管理 -->
    <context:property-placeholder location="classpath:db.properties"/>

    <!-- 配置数据源,用到刚才配置的连接数据库信息 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="$jdbc.user"></property>
        <property name="password" value="$jdbc.password"></property>
        <property name="driverClass" value="$jdbc.driverClass"></property>
        <property name="jdbcUrl" value="$jdbc.jdbcUrl"></property>
    </bean>

    <!-- 配置Hibernate的session管理工厂 ,它依赖于上面的数据源dataSource ref引用 -->
    <bean id="sessionFactoryBean" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>

        <!-- 导入刚才配置的hibernate基本属性, classpath表示src目录下 -->
        <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>

        <!-- 这表示导入实体类根据Hibernate生成的xml文件(有插件比较好,自动生成自己改点就好了) -->
        <property name="mappingLocations" value="classpath:com/ee/ems/entities/*.hbm.xml"></property>
    </bean>

    <!-- 配置事务管理器 它依赖于上面配置的session管理工厂 。。所以一个依赖一个,记着这三个的关系就好配了 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactoryBean"></property>
    </bean>

    <!-- 事务扫描版,它的value值默认是上面配得transactionManager,所有可以省掉不写 -->
    <tx:annotation-driven/>

</beans>

好了,到这里SSH就配好了,额Structs2.xml没有是吧,额,它的源码包有一个最简单的blank例子,整合也跟它没什么关系我觉得…它是靠那个插件包struts2-spring-plugin-2.3.15.3.jar跟spring连在一起的。嗯,好了。接下来来集成SpringShecurity,我们前面已经在web.xml中配置了SpringShecurity的拦截器。现在在src目录下建ApplicationContext-security.xml。只要是ApplicationContext*.xml格式的就行,因为前面配置web.xml配置spring监听器的时候初配得始化参数就是源路径下这个格式的文件。进去看看怎么配得吧

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- http协议,自动配置一些熟悉 -->
    <security:http auto-config="true">

        <!--登陆相关配置  -->
        <!-- login-page指定登陆页面 -->
        <!-- username-parameter登陆页面表达中对应用户名密码的字段 -->
        <!-- login-processing-url登陆处理交给SpringSecurity来做 值对应表单action=security-login-->
        <!-- authentication-success-handler-ref登陆成功由实现了AuthenticationSuccessHandler接口的类来处理,这个我们自己实现由Spring扫描拿到引用 ,弄完配置进去看-->
        <security:form-login

            login-page="/index.jsp"

            username-parameter="loginName"
            password-parameter="password"

            login-processing-url="/security-login"

            authentication-failure-handler-ref="myAuthenticationFailHandlerRef"
            authentication-success-handler-ref="myAuthenticationSuccessHandlerRef"

        />

        <!-- 同上理, invalidate-session默认即为true让session失效,所以不用写-->
        <security:logout
            logout-url="同上理"
            success-handler-ref="同上理"
            invalidate-session="true"

            />

    </security:http>

    <!-- 权限管理配置 -->
    <security:authentication-manager>
        <!--user-service-ref指向实现了UserDetailsService接口的类的对象的引用,这里赋予user各个属性来处理后面的登陆和权限管理,等下进去看  -->
        <security:authentication-provider user-service-ref="myUserDetailsService">

            <!-- 密码采用md5加密方式,由用户名作为加盐处理,注意,这里的user-property参数一定是username无论你表单是loginName还是什么 -->
            <security:password-encoder hash="md5">
                <security:salt-source user-property="username"/>
            </security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>

</beans>

好,上面配置文件讲到两个自己实现的类,先来看MyAuthenticationSuccessHandlerRef处理登陆成功的

@Component
public class MyAuthenticationSuccessHandlerRef implements AuthenticationSuccessHandler

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
            HttpServletResponse response, Authentication arg2) throws IOException,
            ServletException 
        // TODO Auto-generated method stub
        System.out.println("success");
        request.getRequestDispatcher("/login").forward(request, response);
    

看名字就知道,成功后调用到原先Struct2的登陆处理,因为我这是后面集成的,也可以自己根据逻辑处理,到这可能回想如何拿到登陆的user对象是吧,先来看看上面还实现的一个类

@Component
public class MyUserDetailsService implements UserDetailsService

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException 
        // TODO Auto-generated method stub
        System.out.println(username);
        String password="3dd8cce415a5983df873a809003dedb3"; //从数据库中查(模拟的正确密码z8z87878账号zdmina md5加盐处理后,下面main就是)
        boolean enabled=true;//是否可用
        boolean accountNonExpired = true; //账户没有过期
        boolean credentialsNonExpired = true;//凭证没有过期
        boolean accountNonLocked = true;//账户没有被锁定
        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new GrantedAuthorityImpl("ROLE_ADMIN")); //权限必须以ROLE开头,这也应该从数据库中查
        MySecurityUser user = new MySecurityUser(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);

        Employee employee = new Employee();
        employee.setLoginName(username);
        employee.setPassword(password);
        user.setEmployee(employee);
        //返回user对象,然后SpringSecurity将根据这个来判断你是不是能登陆
        return user;
    

    public class MySecurityUser extends User

        private Employee employee;


        public Employee getEmployee() 
            return employee;
        


        public void setEmployee(Employee employee) 
            this.employee = employee;
        



        public MySecurityUser(String username, String password,
                boolean enabled, boolean accountNonExpired,
                boolean credentialsNonExpired, boolean accountNonLocked,
                Collection<? extends GrantedAuthority> authorities) 
            super(username, password, enabled, accountNonExpired, credentialsNonExpired,
                    accountNonLocked, authorities);
            // TODO Auto-generated constructor stub
        

    

    //SpringSecurity的根据用户名md5加盐处理加密.帮助我们模拟数据
    public static void main(String[] args) 

        Md5PasswordEncoder md5PasswordEncoder = new Md5PasswordEncoder();
        String encodePassword = md5PasswordEncoder.encodePassword("z8z87878", "admina");
        System.out.println(encodePassword);
    

好了,上面我们根据数据空中存储的用户密码,权限等属性来构造user去判断能否登陆。登陆成功后我们可以通过SecurityContextHolder.getContext().getAuthentication().getPrincipal()来获取user对象。

    到这里,好像我们只用到了密码,并没有用到权限authentication对吧,权限是不能然我们随便访问哪个页面的,所以我们需要去配置权限 ,权限我们不能在xml文件中静态配置,我们需要根据数据库中存储的页面路径和权限对应表来设置,这里动态设置SpringSecurity的FilterSecurityInterceptor类对象的SecurityMetadataSource来设置url和权限的对应关系.我们先来准备SecurityMetadataSource
@Component
public class MyFilterInvocationSecurityMetadataSource implements FactoryBean<DefaultFilterInvocationSecurityMetadataSource>

    @Override
    public DefaultFilterInvocationSecurityMetadataSource getObject()
            throws Exception 
        // TODO Auto-generated method stub

        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<>();

        //模拟从数据库中查询出
        RequestMatcher requestMatcher = new AntPathRequestMatcher("/list.jsp");
        Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
        configAttributes.add(new SecurityConfig("ROLE_ADMIN")); //模拟,这里可能对应不止这一个权限,当然也不止这一个路径

        requestMap.put(requestMatcher, configAttributes);

        DefaultFilterInvocationSecurityMetadataSource dfsms = new DefaultFilterInvocationSecurityMetadataSource(requestMap);
        return dfsms;
    

    @Override
    public Class<?> getObjectType() 
        // TODO Auto-generated method stub
        return DefaultFilterInvocationSecurityMetadataSource.class;
    

    @Override
    public boolean isSingleton() 
        // TODO Auto-generated method stub
        return true;
    

准备好SecurityMetadataSource后,怎么把它装配到FilterSecurityInterceptor中呢,FilterSecurityInterceptor是服务启动时Spring自动加载的,Spring有一个BeanPostProcessor接口,只要实现了它,并把它加上注解交给Spring管理,那么当Spring加载其他类实例化它们的对象时,都会经过我们定义的这个类被Spring实例化好的对象,Spring优先实例化它,然后等着FilterSecurityInterceptor经过来给它设置属性

@Component
public class MyBeanProcessing implements BeanPostProcessor

    private boolean isSet = false;

    private FilterSecurityInterceptor filterSecurityInterceptor;

    @Autowired
    private MyFilterInvocationSecurityMetadataSource myFilterInvocationSecurityMetadataSource;

    //其它bean实例化好后,要经过这里
    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException 
        // TODO Auto-generated method stub

        if(arg0 instanceof FilterSecurityInterceptor)
            this.filterSecurityInterceptor = (FilterSecurityInterceptor) arg0;
        else if(arg0 instanceof MyFilterInvocationSecurityMetadataSource)
            this.myFilterInvocationSecurityMetadataSource = (MyFilterInvocationSecurityMetadataSource) arg0;
        

        if(!isSet && filterSecurityInterceptor != null && myFilterInvocationSecurityMetadataSource != null)

            try 
    //改变熟悉          filterSecurityInterceptor.setSecurityMetadataSource(myFilterInvocationSecurityMetadataSource.getObject());
             catch (Exception e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
            isSet = true;
        
        return arg0;
    

    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException 
        // TODO Auto-generated method stub
        return arg0;
    

嗯。整合完了。以后忘了也可以自己看看

以上是关于集成SSH和SpringSecurity的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security (4.0.1) 与 AngularJS 的集成。每次用户输入无效凭据时都会弹出基本身份验证

Spring Security - Struts2 集成

170711spring boot 集成shiro

品优购商城项目安全框架SpringSecurity

Spring Security 集成 CAS(基于HTTP协议版本)

SpringBoot集成SpringSecurity+CAS