关闭

spring security 自定义 openid

标签: spring securityopenid
747人阅读 评论(0) 收藏 举报
分类:

目标 利用spring security实现与自定义 openid的对接

大概说一些spring security的账户验证的流程(太细的地方我也不清楚)
1. 对未登陆的用户会被AuthenticationProcessingFilter拦截进行处理,这里主要是读取用户的信息(如果是密码登陆就是在这里获取账号(username)和密码(password),如果是openid就可以在这里让用户跳转到openid service)
2. 在Filter中会生成用户的验证的信息Authentication
3. 然后有会有一个providerManager负责管理改filer所需provider,然后循环调用provider的authenticate方法进行用户,对于每一个provider都有一个对应的userDetailsService进行校验(对于密码和账号就在这里验证,对于openid前面在filter中就有一个标志来表示openid验证情况)
4. 然后成功就会调用登陆成功的handle,失败调用失败的handle

这里写图片描述

其中 vilidate respoense到 openIDConsumer是我们可以自己定义的openid的验证方式,还有userDetails也是可以我们自定义

<http>
...
<!--首先在http标签里面注释掉原来的登陆拦截器,然后在这里加入自定义的openidfilter-->
<custom-filter ref="openidLoginFilter" after="PRE_AUTH_FILTER"/>
...
</http>
<!--自定义的拦截器,然后自定义登陆成功与失败的Handle和自定义的provider-->
<beans:bean id="openidLoginFilter"
                class="com.netease.urs.monitor.filter.MySpecialAuthenticationFilter">
    <beans:property name="authenticationManager" ref="authenticationManager"/>
    <beans:property name="authenticationSuccessHandler"
                        ref="authenticationSuccessHandler"/>
    <beans:property name="authenticationFailureHandler"
                        ref="authenticationFailureHandler"/>
</beans:bean>

<!--这里显示声明使用openidAuthenticationProvider(spring-security-openid),然后对应的userServiceDetail使用我们自定义的-->
<authentication-manager alias="authenticationManager">
        <authentication-provider ref="openidAuthenticationProvider"/>
</authentication-manager>

<beans:bean id="openidAuthenticationProvider"
                class="org.springframework.security.openid.OpenIDAuthenticationProvider">
    <beans:property name="userDetailsService" ref="openidUserService"/>
</beans:bean>

<!--自定义userDetailService-->
<beans:bean id="openidUserService" class="com.netease.urs.monitor.filter.CustomUserDetailsService">
    <beans:property name="roleDao" ref="roleDao" />
    <beans:property name="userDao" ref="userDao" />
    <beans:property name="roleIds">
        <beans:array>
            <beans:value>${core.loginuser}</beans:value>
        </beans:array>
    </beans:property>
</beans:bean>

下面是自定义的openid filter 代码,如果请求的参数里面没有openid.identity就跳转到openid登陆界面,然后对返回的链接也是这个filter拦截的url,这个时候就会进行一些列的参数校验等,具体的逻辑是封装到OpenIdServiceForNetease 中的

public class MySpecialAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private Logger logger = Logger.getLogger(MySpecialAuthenticationFilter.class);

    @Autowired
    private OpenIdServiceForNetease openIdServiceForNetease;

    public MySpecialAuthenticationFilter() {
        super("/login/openid");
    }


    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        // 这里可以实现自己的openid的验证过程
        String identity = request.getParameter("openid.identity");
        if (!StringUtils.hasText(identity)) {
            if (StringUtils.isEmpty(openIdServiceForNetease.getSavedAsscioHandle())) {
                openIdServiceForNetease.associate();
            }
            String url = openIdServiceForNetease.buildRedirectUrl();
            try {
                response.sendRedirect(url);
            } catch (IOException e) {
                logger.debug("重定向到Openid service error" + e.getMessage());
            }
            return null;

        } else {
            try {
                if (!openIdServiceForNetease.check(request)) {
                    throw new AuthenticationServiceException("Consumer error");
                }
            } catch (IOException e) {
                throw new AuthenticationServiceException("service exception" + e.getMessage());
            }
            OpenIDAuthenticationToken token = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS, identity, "123", new ArrayList<OpenIDAttribute>());

            token.setDetails(authenticationDetailsSource.buildDetails(request));

            // delegate to the authentication provider
            Authentication authentication = this.getAuthenticationManager().authenticate(token);
            return authentication;
        }
    }
}

UserDetailService代码,这里就是对登陆成功的用户进行一些列的权限管理。

public class CustomUserDetailsService extends UserDetailsServiceImpl {

    private Long[] roleIds;
    private Collection<BaseRole> roles;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //测试用,这里面可以写自己的角色权限管理
        UserDetails userDetails = super.loadUserByUsername("admin");
        loadDefaultRoles();
        @SuppressWarnings("unchecked")
        Collection<BaseRole> authorities = (Collection<BaseRole>) userDetails.getAuthorities();
        for (BaseRole grantedAuthority : roles) {
            if (!exists(authorities, grantedAuthority.getId())) {
                authorities.add(grantedAuthority);
            }
        }
        return userDetails;
    }

    private boolean exists(Collection<BaseRole> authorities, Long roleId) {
        for (BaseRole authority : authorities) {
            if (authority.getId().longValue() == roleId.longValue()) {
                return true;
            }
        }
        return false;
    }

    private void loadDefaultRoles() {
        if (roles == null) {
            roles = new ArrayList<BaseRole>();
            for (Long roleId : roleIds) {
                roles.add(getRoleDao().load(Role.class, roleId));
            }
        }

    }

    public Long[] getRoleIds() {
        return roleIds;
    }

    public void setRoleIds(Long[] roleIds) {
        this.roleIds = roleIds;
    }

}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:52505次
    • 积分:1180
    • 等级:
    • 排名:千里之外
    • 原创:66篇
    • 转载:10篇
    • 译文:0篇
    • 评论:10条
    最新评论