JHipster一知半解- 3.7security-安全

回文集目录:JHipster一知半解

JHipster选型 spring-security

Jhipster是基于Srping-boot的架构,那么选择spring-security(以下简称SS)也是自然而然的。使用spring-security-starter也确实可以快速的搭建一个基于角色的访问控制(RBAC)的安全架构。总的来说,SS相关配置是JHipster配置中最复杂的一部分,毕竟SS本身相当复杂,虽然已经基于spring-boot进行对应的简化,依旧代码较多,关联模块多,需要仔细琢磨.

pom.xml


    org.springframework.boot
    spring-boot-starter-security


    org.springframework.security
    spring-security-data

基本上就是标准化的starter化配置,通过引入spring-security-config,spring-security-web(间接依赖spring-security-core) ,把spring-security相关的lib包引入项目。
然后通过spring-boot-atuoconfigure中org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration对项目进行安全配置。
注意:spring-security-data不包含在starter中,需要单独引用。

JHipster安全配置代码

总的来说,JHipster与安全配置代码还是比较多的,lib库和生成的代码中都有涉及。以config/SecurityConfiguration作为安全配置入口,使用其他个性化的安全配置类。

类注解上:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

@EnableWebSecurity是一个启SS的全局开关,EnableGlobalMethodSecurity是启用启用全局方法安全的开关。(这里推荐spring in action 第九章,第14章),本质上,SS提供基于Filter的web安全性支持。其初始化一个DelegatingFIlterProxy完成对http请求的逐层过滤。当然,配置也就是控制这个过滤器Filter的控制范围,控制力度。

构造方法:

public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService,JHipsterProperties jHipsterProperties, RememberMeServices rememberMeServices,
        CorsFilter corsFilter) {
        }

通过构造器注入,传入AuthenticationManagerBuilder这里蛮奇怪的,实际上只是在init()中使用,完全可以在onfigure(AuthenticationManagerBuilder authenticationManagerBuilder)中执行一样的动作。
UserDetailsService实际注入的是security/UserDetailsService类,完成从数据库jhi_user表中读取用户信息(包括权限)

@Component("userDetailsService")
public class DomainUserDetailsService implements UserDetailsService

rememberMeServices是实际注入的是security/PersistentTokenRememberMeServices类,完成从jhi_persistent_token读取用户的会话token,以完成有效期类完成免登陆验证。

@Service
public class PersistentTokenRememberMeServices extends
    AbstractRememberMeServices
    

corsFilter配置本身是在WebConfigurer里面的,这里引入依赖的目的是为了UsernamePasswordAuthenticationFilter之前加入corsFilter(下标为5)进行CORS的校验。

@Bean
    public AjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandler() {
        return new AjaxAuthenticationSuccessHandler();
    }

    @Bean
    public AjaxAuthenticationFailureHandler ajaxAuthenticationFailureHandler() {
        return new AjaxAuthenticationFailureHandler();
    }

    @Bean
    public AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler() {
        return new AjaxLogoutSuccessHandler();
    }

这三个bean都是jhipster.jar提供的工具bean,用来在restful调用时出现成功,失败,以及登出请求时候的处理器Handler。
目前4.10以及不用了,@Import(SecurityProblemSupport.class),使用了zalando的problemSupport作为替代品

两个configure()方法

@Override
    public void configure(WebSecurity web) throws Exception {
        //HttpMethod.OPTIONS和以下url不纳入ss的控制范围(高层次控制)
        web.ignoring()
            .antMatchers(HttpMethod.OPTIONS, "/**")
            .antMatchers("/app/**/*.{js,html}")
            .antMatchers("/i18n/**")
            .antMatchers("/content/**")
            .antMatchers("/swagger-ui/index.html")
            .antMatchers("/test/**")
            .antMatchers("/h2-console/**");
    }
 @Override
    protected void configure(HttpSecurity http) throws Exception {
        //设置CookieCsrfTokenRepository为false,提高安全性
        http
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
        //在corsFilter之前增加UsernamePasswordAuthenticationFilter,并设置验证错误处理为http401UnauthorizedEntryPoint
        .and()
            .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
            .exceptionHandling()
            .authenticationEntryPoint(http401UnauthorizedEntryPoint())
        //配置rememberMe由自定义的rememberMeServices(PersistentTokenRememberMeServices类)提供,cookie是保存在"remember-me"参数中。
        .and()
            .rememberMe()
            .rememberMeServices(rememberMeServices)
            .rememberMeParameter("remember-me")
            .key(jHipsterProperties.getSecurity().getRememberMe().getKey())
        //配置登陆的URL为/api/authentication,注意前端的传递的用户名为j_username参数,密码为j_password参数
        .and()
            .formLogin()
            .loginProcessingUrl("/api/authentication")
            .successHandler(ajaxAuthenticationSuccessHandler())
            .failureHandler(ajaxAuthenticationFailureHandler())
            .usernameParameter("j_username")
            .passwordParameter("j_password")
            .permitAll()
        //配置登出的URL为/api/authentication,登出成功调用ajaxLogoutSuccessHandler,返回200
        .and()
            .logout()
            .logoutUrl("/api/logout")
            .logoutSuccessHandler(ajaxLogoutSuccessHandler())
            .permitAll()
        //配置禁止X-Frame-Options,防止iframe内框架调用,提高安全性
        .and()
            .headers()
            .frameOptions()
            .disable()
        //配置以下URL的权限控制(如management需要ADMIN权限),可以看出,这里的权限控制是通过硬编码方式进行的
        .and()
            .authorizeRequests()
            .antMatchers("/api/register").permitAll()
            .antMatchers("/api/activate").permitAll()
            .antMatchers("/api/authenticate").permitAll()
            .antMatchers("/api/account/reset_password/init").permitAll()
            .antMatchers("/api/account/reset_password/finish").permitAll()
            .antMatchers("/api/profile-info").permitAll()
            .antMatchers("/api/**").authenticated()
            .antMatchers("/management/health").permitAll()
            .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/v2/api-docs/**").permitAll()
            .antMatchers("/swagger-resources/configuration/ui").permitAll()
            .antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN)
        ;

    }

重点是authorizeRequests()的相关配置,是SS实现对通用角色控制的地方。

@Bean
    public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
        return new SecurityEvaluationContextExtension();
    }

这里定义了spring-security-data唯一的一个类,SecurityEvaluationContextExtension
但是实际上spring-boot在1.3以后,会判断其引入状态进行自动配置,因此这段代码本身并没其什么作用。

@Configuration
@ConditionalOnClass({ SecurityEvaluationContextExtension.class,
        EvaluationContextExtensionSupport.class })
public class SecurityDataConfiguration {

    @ConditionalOnMissingBean(SecurityEvaluationContextExtension.class)
    @Bean
    public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
        return new SecurityEvaluationContextExtension();
    }

}

security包中安全配置
AuthoritiesConstants.java
简单的枚举类,系统的提供的角色都在这里罗列.默认只有ADMIN,USER,ANONYMOUS三种权限.(实际上只用了前2个-jhi_authroizes表中).
SecurityUtils是一个工具类,用来从SecurityContextHolder取出securityContext,,并判断其用户名,是否验证等信息.
具体使用场景-rest resource.
UserResource.java中

PostMapping("/users")
    @Timed
    @Secured(AuthoritiesConstants.ADMIN)
    public ResponseEntity createUser(){};

综上所述,JHipster在SecurityConfiguration,AuthoritiesConstants,以及需要的resource中加上@Secured注解,三个地方共同起作用,进行SS的基于角色的安全配置.实际上SecurityConfiguration和@Secured是平行的,两边只需要有一边配置即可.

不使用基于session的安全配置。

TODO:此处应该有图,构建时候的选项

JWT

单体应用使用Session会话来验证用户登录情况固然可行,但是毕竟传递的信息有限(token),如果变为多机系统,处理分布session的问题就是相当麻烦的事情.此时,就可以祭出JWT(Json web token),使用自包含的json信息进行验证.由于配置简单,可扩展性好,已经成为了JHipster的推荐选项了.

security.jwt.JWTConfigurer
作为SecurityConfigurerAdapter的子类,通过configure(HttpSecurity http)对SS进行配置,本质为new 出一个JWTFilter,并放到UsernamePasswordAuthenticationFilter之前.
security.jwt.JWTFilter
其doFilter调用了tokenProvider对HttpServletRequest中jwt数据进行解析,校验.
security.jwt.TokenProvider
这里利用了jsonwebtoken提供的Jwts工具,进行JWT的数据构建builder(),token验证parseClaimsJws()

ouah2

部分基本概念

应用于开放网络的第三方授权。
用户- 网站A - 网站B (通过授权,网站B能读取网站A中用户的“部分”私有信息,操作“部分”私有数据
----用微信授权登陆游戏理解。
名词:
Third-party application,Http Service, Resource Owner,User Agent, Authorization Sever, Resource Server。
基本流程:
1.用户打开客户端(浏览器),访问服务消费端,客户端要求用户授权(站点的微信登陆按钮)
2.用户同意授权给Client,与 Authorization Server交互.(此时是在微信网站上)
3.客户端向认证服务器申请令牌。
4.认证服务器发放令牌
5.客户端(游戏网站上),使用令牌请求“受保护的”资源
6.资源服务器验证令牌,开发资源。
其中关键流程是第二部,怎样才能给客户端授权。(授权码模式,简化模式,密码模式,客户端模式)

JHipster支持的Oauth2

JHipster使用了spring-security-oath2作为OATH2认证的依赖。这块与ss结合的很好,也算是ss的优势之一了。

可分为2块,一块作为认证服务器,对外暴露资源,一块作为客户端,访问facebook,google,Twitter资源。

  1. OATH2服务器

    org.springframework.security.oauth
    spring-security-oauth2

security:
    basic:
        enabled: false
    oauth2:
        resource:
            filter-order: 3

xml增加依赖,yml增加spring.oauth2的配置

另外,增加OAuth2ServerConfiguration,通过
@EnableResourceServer,@EnableAuthorizationServer,对外暴露OATH的认证服务,具体代码不再赘述。注意,这里试简化处理了,AuthorizationServer和ResourceServer做了一体化处理,实际上是可以拆分的。

  1. SSO客户端
    这个相当更加麻烦一点,引入的依赖比较多

    org.springframework.social
    spring-social-security


    org.springframework.social
    spring-social-google
    ${spring-social-google.version}


    org.springframework.social
    spring-social-facebook


    org.springframework.social
    spring-social-twitter

yml需要配置sso的client-id和client-secet

spring:
    social:
        # see https://developers.google.com/+/web/signin/server-side-flow#step_1_create_a_client_id_and_client_secret
        google:
            client-id: xxx
            client-secret: xxx

        # see https://developers.facebook.com/docs/facebook-login/v2.2
        facebook:
            client-id: xxx
            client-secret: xxx

        # see https://apps.twitter.com/app/
        twitter:
            client-id: xxx
            client-secret: xxx

代码增加了security.social.CustomSignInAdapter和config.social.SocialConfiguration作为sso登陆的衔接器。
值得注意的是SocialConfiguration的@EnableSocial,需要配置和覆盖的代码还是比较多的。
在service中增加了SocialService,并修改了UserService,在保证删除用户能同步删除social用户的数据。
,web.rest中也增加了SocialController,作为sso服务暴露出去,作为第三方登陆的验证地方,具体代码也不再赘述。

uaa

暂时没有用,略过

升级空间

从代码分析中,虽然JHipster利用了spring-boot对SS配置,一定程度上简化了SS的复杂度,但是其权限管理,特别是系统角色的定义,角色与权限之间的对应,还是硬编码进行的.如果稍复杂的系统,这样做的灵活性就比较低,权限的修改比如引起代码修改,升级.
后续应该参考下面文档,建立一套比较完整的权限体现,提高其灵活性.

资源和书籍推荐

spring security的原理及教程

http://blog.csdn.net/u012367513/article/details/38866465

SPRING SECURITY JAVA配置

http://www.importnew.com/5520.html

http://www.importnew.com/5641.html

Spring Security4.1的官方文档翻译

http://www.tianshouzhi.com/api/tutorials/spring_security_4/250

Spring Security 官方Demo

https://github.com/spring-projects/spring-security-oauth

Spring Security 概念基础 验证流程

http://www.cnblogs.com/final-elysion/p/6074572.html
http://www.baeldung.com/spring-security-two-factor-authentication-with-soft-token

JSON Web Token - 在Web应用间安全地传递信息

http://blog.leapoahead.com/2015/09/06/understanding-jwt/
http://blog.leapoahead.com/2015/09/07/user-authentication-with-jwt/

JWT 简介

https://segmentfault.com/a/1190000005047525

Restful安全认证及权限的一种解决方案

http://nettm.iteye.com/blog/2304221

JWT在身份认证方面的应用

http://www.jianshu.com/p/fcc1a6482143

基于JWT(Json Web Token)的授权方式

http://www.cnblogs.com/grissom007/p/6294746.html

什么是 JWT -- JSON WEB TOKEN

http://www.jianshu.com/p/576dbf44b2ae

理解OAuth 2.0

http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

OAuth 2 开发人员指南(Spring security oauth2)

http://www.oschina.net/translate/oauth-2-developers-guide

OAuth与OpenID

http://www.cnblogs.com/neutra/archive/2012/07/26/2609300.html

帮你深入理解OAuth2.0协议

http://blog.csdn.net/seccloud/article/details/8192707

Spring Security 与 Oauth2 整合 步骤

http://blog.csdn.net/monkeyking1987/article/details/16828059

Spring Boot and OAuth2

http://spring.io/guides/tutorials/spring-boot-oauth2/
http://blog.csdn.net/neosmith/article/details/52539927
http://blog.csdn.net/u011686226/article/details/54707302

你可能感兴趣的:(JHipster一知半解- 3.7security-安全)