Springecurity2.0.4+OpenID完整配置攻略

Spring Security2.04+OpenID配置攻略

 

 

 

 

 

 

目 录

 

1.QQ互联中的OpenID 3

配置环境 3

3、 Spring Securityxml配置 3

4、 OpenID登录页 17

5、 申请OpenID 账号 17

6、 在本地登录OpenID 18

7、 其他注意事项 19

 


1.QQ互联中的OpenID

    QQ 互联接口中,在QQ登陆成功后,会返回一个OpenID,但是此OpenID是一个大写字母和数字的组合。与一般的OpenID的格式不同,正常的OpenID应该是http开头的URL格式,例如http://zhangsan.openid.org.cn/ ,本文介绍的是国际通用的OpenID认证协议+Spring Security配置过程。

2.配置环境

本文的介绍的配置过程是在OpenJWeb2.63环境下配置的,OpenJWeb2.63集成了S2SHSpring Security2.0.4,大家也可以自己搭建一个S2SH+Spring Security2.04的环境,在环境搭建好以后,我们需要从网上找到openid4java-0.9.8.jar,放到WEB-INF\lib目录下。有了这个驱动,我们就可以在spring security中进行openID的认证登陆。

另外,我们需要将spring-security-openid-2.0.4.jar放到lib目录中。

web.xml文件中,我们需要增加一段配置以支持openID认证过滤器:

        springSecurityFilterChain

        /j_spring_openid_security_check 

    

    

3、Spring Securityxml配置

   特别注意Spring Security2.0.4的头部配置,因为网上版本众多,有的是以作为bean标签,有的是以 作为bean标签,如果不设置正确的xml头部,则xml中无法使用像

    

这种标签。可以参考下面的xml头:

 

      

 

  xmlns:p="http://www.springframework.org/schema/p"     

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

        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-2.5.xsd

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

        default-autowire="byType" default-lazy-init="true">

 

网上有很多pdf格式的spring security配置文档,里面介绍了

    

使用 就可以引入OpenID认证。

但是经过试验发现,使用 以后,通过spring_openid_security_check进行OpenID认证,则无法使用j_spring_security_check做最常用的本地数据库认证。显然我们希望是两者同时支持。所以我们就不能使用缺省的方式,因此上面的那段配置可以在xml中删除。

参考现有的authenticationProcessingFilter的配置方式,我们需要增加以下配置来满足openID认证授权:

          class="org.springframework.security.util.FilterChainProxy">      

              

            

                    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON      

                    PATTERN_TYPE_APACHE_ANT      

                    /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,openIDAuthenticationFilter,securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterSecurityInterceptor      

                ]]>      

              

          

上面蓝字部分是增加了一个openIDAuthenticationFilter ,下面是增加的这个bean的配置:

   

          class="org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter"

   p:authenticationManager-ref="authenticationManager"     

          p:authenticationFailureUrl="/secure/openid.jsp"

    p:defaultTargetUrl="/apps/v22/ui/frame/main.jsp"

          p:filterProcessesUrl="/j_spring_openid_security_check"     

  />      

 p:authenticationFailureUrl指明认证失败跳转的页面。p:defaultTargetUrl指明认证成功跳转的页面。p:filterProcessesUrl指明openID的认证过滤器URL.

authenticationManager Bean中,原来有      ,需要增加一个针对OpenID的Provider,见下文(蓝字是针对OpenID增加的Provider):

          class="org.springframework.security.providers.ProviderManager"     

          p:sessionController-ref="concurrentSessionController">      

              

                  

                      

       

                  

              

      

下面我们要设置openidAuthenticationProvider Bean:

 

 

class="org.springframework.security.providers.openid.OpenIDAuthenticationProvider">

完整的配置(openjweb中此配置文件为D:\project\openjweb\src\java\applicationContext-security-new.xml):

 

      

 

  xmlns:p="http://www.springframework.org/schema/p"     

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

        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-2.5.xsd

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

        default-autowire="byType" default-lazy-init="true">

 

  

  

       

    

          class="org.springframework.security.util.FilterChainProxy">      

              

            

                    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON      

                    PATTERN_TYPE_APACHE_ANT      

                    /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,openIDAuthenticationFilter,securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterSecurityInterceptor      

                ]]>      

              

          

     

   

          class="org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter"

   p:authenticationManager-ref="authenticationManager"     

          p:authenticationFailureUrl="/secure/openid.jsp"

    p:defaultTargetUrl="/apps/v22/ui/frame/main.jsp"

          p:filterProcessesUrl="/j_spring_openid_security_check"     

  />      

    

          class="org.springframework.security.context.HttpSessionContextIntegrationFilter"/>      

          

    

          class="org.springframework.security.ui.logout.LogoutFilter">      

              

              

              

              

                  

                      

                      

                      

                  

              

          

    

  

          class="org.openjweb.core.springsecurity.UserAuthenticationProcessingFilter"     

          p:authenticationManager-ref="authenticationManager"     

          p:authenticationFailureUrl="/common/chooseLogin.jsp?login_error=1"

  p:defaultTargetUrl="/apps/v22/redirect.jsp"

          p:filterProcessesUrl="/j_spring_security_check"     

          p:rememberMeServices-ref="rememberMeServices"/> 

           

    

    

          class="org.springframework.security.providers.ProviderManager"     

          p:sessionController-ref="concurrentSessionController">      

              

                  

                      

       

                      

                  

              

          

          

    

          class="org.springframework.security.concurrent.ConcurrentSessionControllerImpl"     

          p:maximumSessions="1000"     

          p:exceptionIfMaximumExceeded="true"     

          p:sessionRegistry-ref="sessionRegistry"     

          p:messageSource-ref="messageSource"/>      

    

          class="org.springframework.security.concurrent.SessionRegistryImpl"/>      

   

          class="org.springframework.context.support.ReloadableResourceBundleMessageSource"     

          p:basename="/WEB-INF/classes/messageResource_zh_CN"/>      

   

          class="org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter"/>      

     

    

          class="org.springframework.security.ui.rememberme.RememberMeProcessingFilter"     

          p:authenticationManager-ref="authenticationManager"     

          p:rememberMeServices-ref="rememberMeServices"/>   

 

    

    

          class="org.springframework.security.providers.anonymous.AnonymousProcessingFilter"     

          p:key="springsecurity"     

          p:userAttribute="anonymousUser,ROLE_ANONYMOUS"/>      

     

   

          class="org.springframework.security.ui.ExceptionTranslationFilter"     

          p:accessDeniedHandler-ref="accessDeniedHandler"     

          p:authenticationEntryPoint-ref="authenticationEntryPoint"/>      

     

          class="org.springframework.security.ui.AccessDeniedHandlerImpl"     

          p:errorPage="/accessDenied.jsp"/>      

     

          class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint"     

          p:loginFormUrl="/common/chooseLogin.jsp"     

          p:forceHttps="false"/>      

    

 

 

 

class="org.springframework.security.providers.dao.cache.EhCacheBasedUserCache">

 

class="org.springframework.cache.ehcache.EhCacheFactoryBean">

 

class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">

value="classpath:ehcache-security.xml" />

 

 

class="org.springframework.security.intercept.web.FilterSecurityInterceptor">

ref="authenticationManager" />

ref="accessDecisionManager" />

 

 

ref="databaseFilterInvocationDefinitionSource" />

 

      

class="org.springframework.security.vote.AffirmativeBased">

class="org.springframework.security.vote.RoleVoter">

  

 

     

    

          class="org.springframework.security.ui.rememberme.TokenBasedRememberMeServices"     

          p:key="springsecurity"     

          p:userDetailsService-ref="userDetailsService"/>      

     

   

 

    

class="org.springframework.security.providers.dao.DaoAuthenticationProvider">

 

 

class="org.springframework.security.providers.openid.OpenIDAuthenticationProvider">

    

          class="org.springframework.security.providers.encoding.Md5PasswordEncoder"/>      

     

    

     

    

class="org.openjweb.core.springsecurity.UserDetailsServiceImpl">

     

   

class="org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource">

type="org.springframework.security.util.UrlMatcher"

ref="antUrlPathMatcher" />

 

class="org.springframework.security.util.AntUrlPathMatcher" />

 

class="org.openjweb.core.springsecurity.RequestMapFactoryBean"

init-method="init">

 

 

    

          class="org.springframework.security.event.authentication.LoggerListener"/>      

     

    

 

注意配置文件中的这段代码:

    

class="org.openjweb.core.springsecurity.UserDetailsServiceImpl">

org.openjweb.core.springsecurity.UserDetailsServiceImplOpenJWeb中实现Spring Security UserDetailsService接口的实现类。我们 此实现类中增加一段代码,此段代码获取openID认证以后的OpenID账号,检查数据库表comm_user中是否存在此账号,如果不存在,则认证成功后自动向数据库表添加一条账号记录,并且为此账号分配一个网站会员角色。下面是org.openjweb.core.springsecurity.UserDetailsServiceImpl的代码:

package org.openjweb.core.springsecurity;

 

 

 

import org.apache.log4j.Logger;

import org.openjweb.core.dao.IBaseDao;

import org.openjweb.core.entity.CommUser;

import org.openjweb.core.entity.CommUserRole;

import org.openjweb.core.service.IDBSupportService;

import org.openjweb.core.service.ServiceLocator;

import org.openjweb.core.util.StringUtil;

 

import org.springframework.dao.DataAccessException;

import org.springframework.security.userdetails.UserDetails;

import org.springframework.security.userdetails.UsernameNotFoundException;

 

public class UserDetailsServiceImpl   implements IUserService 

{

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

private IBaseDao defaultDao;

public UserDetailsServiceImpl (IBaseDao dao)

{

this.defaultDao = dao;

}

 

public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException 

{

CommUser user = null;

try

{

user = (CommUser)this.defaultDao.findById(CommUser.class.getName(), "loginId", userName);

    if(user.getIsInUse()!=null&&user.getIsInUse().equals("Y"))

    {

    }

    else

    {

    logger.info("用户被锁定......");

    throw new UsernameNotFoundException(userName); //被锁定

    }

}

catch(Exception ex)

{

//检查如果是openid格式的,则生成一个对应的openid用户--必填项先默认生成,用户再自己修改

if(userName.startsWith("http://")||userName.startsWith("https://"))

{

IDBSupportService service = (IDBSupportService)ServiceLocator.getBean("IDBSupportService3");

user = new CommUser();

Long serial = null;

try

{

serial = service.getSerial();

}

catch(Exception ex1)

{

//

}

user.setUserId(serial);

user.setRowId(StringUtil.getUUID());

user.setLoginId(userName);

user.setComId("C0001");

user.setIsPortalMember("Y");//设置为网站会员,这种情况一般是网站会员

user.setUsername(userName);//暂时以用户id作为用户名

user.setUserEmail(serial.toString()+"openjweb.com");//生成一个默认的

user.setPassword("unused");

user.setUserMobile(serial.toString());//生成一个默认的由用户自己修改

user.setIsInUse("Y");

user.setEmpNo(serial.toString());//工号

user.setUpdateUid("system");

user.setCreateUid("system");

user.setCreateDt(StringUtil.getCurrentDateTime());

user.setUpdateDt(user.getCreateDt());

user.setCurrFrameCode("06");

user.setCurrSkinCode("sky");

try

{

service.saveOrUpdate(user);

//然后分配门户网站会员角色

CommUserRole roleEnt = new CommUserRole();

roleEnt.setCreateDt(StringUtil.getCurrentDateTime());

roleEnt.setSerialNo(service.getSerial());

roleEnt.setRoleId(new Long(505715));

roleEnt.setUserId(user.getUserId());

service.saveOrUpdate(roleEnt);

}

catch(Exception ex2)

{

}

}

else

{

throw new UsernameNotFoundException(userName);

}

}

return user;

}

 

}

4、OpenID登录页

编写一个jsp,例如openid.jsp,下面是此jsp中的一段form内容:

    

  Login:    

   

      

 

      

     

 

说明:/portal/指的是openjweb的应用路径,如果在webapps根目录可使用/j_spring_openid_security_check ,OpenID输入框的name必须为j_username

 

5、申请OpenID 账号

我们可以到谷歌、微软等openID提供商注册一个openID账号,或者在http://www.openid.org.cn上注册一个账号,例如注册一个baozhengw的账号,则完整的OpenID账号则为:  http://baozhengw.openid.org.cn/

 

6、在本地登录OpenID

运行第四步创建的JSP,见下图:

输入:http://baozhengw.openid.org.cn/

然后点登录,系统会跳转到OpenID服务器(系统会根据openid的域名跳转到对应的服务器),见下图(跳转到http://www.openid.org.cn/): 

输入baozhengw,和注册时的口令,然后点登录,自动跳转到http://localhost:8088/portal/apps/v22/ui/frame/main.jsp(在配置文件中通过redirect.jsp跳转到后台,因为新增用户自动添加了关联角色,所以能进入后台)

 

 

7、其他注意事项

SecurityContextImpl securityContext =(SecurityContextImpl)obj;

Object tmpObj = null;

tmpObj  = securityContext.getAuthentication().getPrincipal();

 

以传统的方式登录,即/j_spring_security_check本地数据库认证的模式,通过getPrincipal()实际返回的是UserDetailsService接口的实现类,在OpenJWeb中是CommUser类,而使用OpenID,则getPrincipal()返回的是OpenID账号,如http://baozhengw.openid.org.cn/ ,所以产品支持OpenID以后,getPrincipal()的返回值类型处理要考虑多种类型。

 

OpenJWeb 开源组织

QQ 29803446

 

你可能感兴趣的:(Java)