单点登录
单点登录,英文是 Single Sign On(缩写为 SSO)。即多个站点共用一台认证授权服务器,用户在站点登录后,可以免登录访问其他所有站点。而且,各站点间可以通过该登录状态直接交互。例如:
业务逻辑的使用
网关鉴权 微服务
没有 需要
鉴权 补充
CAS 是 Central Authentication Service 的缩写 —— 中央认证服务,一种独立开放指令协议,是 Yale 大学发起的一个企业级开源项目,旨在为 Web 应用系统提供一种可靠的 SSO 解决方案。
SSO是一种思想,而CAS只是实现这种思想的一种框架而已
CAS支持oauth2 协议
SSO是一种思想,或者说是一种解决方案,是抽象的,我们要做的就是按照它的这种思想去实现它
OAuth2是用来允许用户授权第三方应用访问他在另一个服务器上的资源的一种协议,它不是用来做单点登录的,但我们可以利用它来实现单点登录。
OAuth2是目前最流行的授权机制,用来授权第三方应用,获取用户数据。允许用户授权B应用不提供帐号密码的方式去访问该用户在A应用服务器上的某些特定资源。
四个角色:
resource owner:资源所有者,这里可以理解为用户。
client:客户端,可以理解为一个第三方的应用程序 即微博 CSDN。
resource server:资源服务器,它存储用户或其它资源。
authorization server:
认证/授权服务器,它认证resource owner的身份,为 resource owner提供授权审批流程,并最终颁发授权令牌(Access Token)。
认证服务器只有一个 sysauth
资源服务器 订单 商品 支付
认证的流程
* authorization_code 授权码模式
* password 密码模式
* implicit 简单模式
* client_credentials 客户端模式
* refresh_token 这个不是一种模式 是支持刷新令牌的意思
一般用于提供给第三方使用
一般不会使用
一般仅用于系统内部使用
一般不会使用
用户:就是注册的用户
客户端:就是我们的前端项目
授权服务器:我们可以专门在后台创建一个专门管授权的微服务
资源微服务:像其他的订单微服务,什么搜索微服务拉都可以看做用户能够访问的资源
如果我们自己去用java实现OAUTH2.0标准,太麻烦了,幸好有spring-security-oauth2这个插件,就简单多了,spring-security-oauth2是基于spring-security框架完整实现oauth2协议的框架,具有oauth2中4种模式访问和第三方登录等功能。
所有授权端点(EndterPoints),意思就是授权微服务启动后 可以访问哪些路径
认证服务器的ip以及端口号 localhost:8500
localhost:8500/oauth/token
路径 |
说明 |
/oauth/authoriz |
授权端点 |
/oauth/token |
令牌端点 获取token |
/oauth/confirm_access |
用户确认授权提交端点 |
/oauth/error |
授权服务错误信息端点 |
/oauth/check_token |
用于资源服务访问的令牌解析端点 |
/oauth/token_key |
提供公有密匙的端点,如果你使用JWT(RSA)令牌的 |
授权的配置信息需要继承AuthorizationServerConfigurerAdapter
将授权的客户端的信息保存到内存里面
@Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin().permitAll(); http.authorizeRequests().antMatchers("/userlogin","/oauth/**").permitAll();// 代表放行 "/login.html","/userlogin","/" http.authorizeRequests().anyRequest().authenticated(); // csrf 方便html 文件 能够通过 http.csrf().disable(); http.cors();//跨域 } @Resource private BCryptPasswordEncoder passwordEncoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("aaa") .password(passwordEncoder.encode("123456")) .roles("ADMIN"); // auth.userDetailsService(userDetailsService).passwordEncoder(getPassword()); } public void printJsonData(HttpServletResponse response, Result result) { try { response.setContentType("application/json;charset=utf8"); // json格式 编码是中文 ObjectMapper objectMapper = new ObjectMapper(); String s = objectMapper.writeValueAsString(result);// 使用ObjectMapper将result转化json为字符串 PrintWriter writer = response.getWriter(); writer.print(s); writer.flush(); writer.close(); }catch (Exception e){ e.printStackTrace(); } } }
访问后登录
登录后获得授权码
localhost:8500/oauth/token?grant_type=authorization_code&code=4WXzET&client_id=admin&redirect_url=http://www.baidu.com&scope=all
登录
获得token
localhost:8500/oauth/authorize?response_type=token&client_id=admin&scope=all
dependency>
安全配置文件中配置认证成功之后使用第三方工具 hutool 发出post请求 生成token 返回客户端
package com.example.controller.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; @Configuration @EnableResourceServer @EnableGlobalMethodSecurity(jsr250Enabled = true,prePostEnabled = true,securedEnabled=true) public class MyResConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() //.access("@RbacConfig.hasPermission(request,authentication)") .and() .csrf().disable(); } @Bean public TokenStore tokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter(){ JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter(); jwtAccessTokenConverter.setSigningKey("test"); // return jwtAccessTokenConverter; } }
测试token是否生效
携带token 访问资源服务器
Authorization 放在headers里面的
Token的值 要求必须是bearer 类型的 token前面加上这个类型