一、sso是什么?
sso(Single Sign On 单点登入)
sso是可以理解为一种概念模型,许多企业有多系统,包括开放系统等,那么将会遇到得问题就是不同系统都需要有登入操作,如果使用sso,那么只需要一次登入就可以访问所有系统,对于使用上来说带来了一点方便。当然对于技术上来讲带来了好处就很大,比如权限可以统一管理,代码从业务系统剥离,或者对外提供服务。
我们想在要做得就是这样一套系统,将采用spring security oauth2.0 jwt(java web token) 来实现。、
什么是JWT?以下资料来自http://www.jianshu.com/p/576dbf44b2ae
Json web token(JWT)是为了网络应用环境间传递声明而执行的一种基于JSON的开发标准(RFC 7519),该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
什么是spring security?(个人理解)
spring security 是spring提供得一套安全架构,对服务资源进行系统性得保护。系统资源包括:uri、静态资源等,凡是需要请求得都可以称为系统资源。
什么是oauth2.0?百度百科https://baike.baidu.com/item/OAuth2.0/6788617?fr=aladdin
oauth2.0 可以理解为是一套为服务端与客户端之间进行服务认证得标准协协议。
以上为一堆废话。
二、使用spring security oauth2.0 jwt 实现我们得权限管理系统得sso,网络上对于sso得技术文章很多,但是当你去踩得时候你会发现各种各样得坑。我就是一步一步踩过来得,踩完之后发现这东西还真是很好用,简单快捷。
以下为部分代码我会把关键得地方讲解到位
关键包
<!--sso 核心包,这里实现自动配置,减少我们大批量得配置工作,使用这个包就不需要再额外引入security包了-->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<!--redis starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--分布式session管理,添加这个包后注解@EnableRedisHttpSession启用session缓存至redis-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!--视图模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
以下两个重要配置
配置一: WebSecurityConfig,重要注解
@EnableWebSecurity
@Order(1) //这个注解一定要填,不然经过security得默认配置
/**
* @Auth yaozhongjie
* @Date 2019/5/2 21:31
**/
@Configuration
@EnableWebSecurity
@Order(1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
SysUserDetailService userDetailService;
@Override
protected void configure(HttpSecurity http) throws Exception {
//由于首页使用得是get请求,所以使用successHandler做个重定向,如果设置得是POST请求 可以直接使用 .successForwardUrl("/index")
AuthenticationSuccessHandler handler=new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.sendRedirect(httpServletRequest.getContextPath()+"/index");
}
};
//设置所有请求进行拦截
http.authorizeRequests()
.anyRequest().authenticated();
http.formLogin()
.loginPage("/login")//登陆页
.loginProcessingUrl("/authentication/form")//登入表单提交地址,这个是默认得
.failureForwardUrl("/login/error")//失败后进行异常转接,需要定义个controller从request中拿到异常信息,然后抛出异常,进行全局异常处理
//.successForwardUrl("/index")//登陆成功后post请求
//.successHandler(handler) //可以处理登陆成功事件
.defaultSuccessUrl("/index") //设置默认登入成功自定义页面,第二个参数为默认页面,默认为false 不使用默认页面,如果设为true使用默认页面
.permitAll();//授权全部权限,也就是不拦截得意思
}
@Override
public void configure(WebSecurity web) throws Exception {
//这里忽略静态文件不校验,假如有配置swagger,也是在这里配置
web.ignoring().antMatchers("/assets/**", "/css/**", "/images/**");
}
@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这里设置从数据库获取用户信息,权限信息
auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
配置二:AuthServerConfig 授权服务器配置
/**
* @Auth yaozhongjie
* @Date 2019/5/2 21:31
**/
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
DataSource dataSource;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients();
security.tokenKeyAccess("permitAll()"); //验证通过后得权限。默认是denyAll()拒绝全部
security.checkTokenAccess("isAuthenticated()");//设置检查access_token,默认拒绝全部
//super.configure(security);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.accessTokenConverter(jwtAccessTokenConverter());
endpoints.tokenStore(jwtTokenStore());
//endpoints.tokenServices(defaultTokenServices());
}
/**
* 配置ClientDetailsService
* 注意,除非你在下面的configure(AuthorizationServerEndpointsConfigurer)中指定了一个AuthenticationManager,否则密码授权方式不可用。
* 至少配置一个client,否则服务器将不会启动。
*/
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
//这里分为好几个客户端类型,有需要可以点进去看,我这里使用的是从数据库获取信息。
//这里使用jdbc template 连接,sql 什么的 内部都给你集成好了。这里做的事情,就是单点登陆的信息校验。
clients.jdbc(dataSource);
}
//以下为token 配置,使用什么token 和如何存储等。在此忽略
@Primary
@Bean
public DefaultTokenServices defaultTokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(jwtTokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Bean
public JwtTokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey("123456");
return jwtAccessTokenConverter;
}
网络上参考了好几篇博客,花了一天一夜把security肯下来了,但是还有很多东西需要去挖掘。还没系统的去挖掘
现在对security基本使用应该没什么问题了。
列出几篇有用的(以下是看了几百篇博文比较有作用的文章。更多的还是不断实验以及查看源码的领悟)
1、security 异常处理参考
https://blog.csdn.net/yuanlaijike/article/details/80250389
2、服务配置连界面都是扒这位博主的另一篇文章。
http://www.cnblogs.com/cjsblog/p/9296361.html
3、官方文档
https://spring.io/projects/spring-security