回文集目录: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资源。
- 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做了一体化处理,实际上是可以拆分的。
- 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