文章目录
- 前言
- 一、单点登录是什么?
- 二、oauth2授权码模式单点登录流程
-
* 1.流程图- 2. 代码相关
- 2. 验证流程
- 总结
前言
oauth2 有四种模式,常用的为密码和授权码,剩下两种几乎不用
- 密码模式,很好理解,就是根据输入的用户名/密码进行登录认证的,最终返回一个合法token
- 授权码(grant_type = authorization_code), 是利用唯一的客户端信息,申请的一个临时授权码,然后根据授权码换取合法token,可以利用这个特性,达到单点登录的效果
一、单点登录是什么?
简而言之: 登录一次,可以访问所有当前网站被信任的其他网站,无需再次登录;
例如:
我登录了淘宝,然后再次访问里面的其他应用的时候,不会再次登录,而是直接就进去了(天猫 聚划算 咸鱼)
1.流程图
操作步骤说明:
- 用户访问服务A,需要使用服务提供商的数据(用户信息),首次访问没有任何信息,需要登录;
- 服务A通过重定向跳转到服务提供商的统一登录页面。在重定向中构建授权码请求,授权许可
- 用户选择是否给予客户端授权访问服务提供商(用户信息)数据的权限
- 输入用户信息,用户给予授权。权限系统通过重定向(redirect_uri)并携带 授权凭证(code)跳转客户端。
- 服务A提供redirect_uri的接口,接受授权码code,将授权凭证(code)发送给鉴权中心服务器,服务A服务器携带授权码(code)、客户端id(client_id)和秘钥(client_secret)向认证服务器请求访问令牌(access_token)
- 鉴权中心认证服务器核对授权码信息,确认无误后,向客户端发送访问令牌(access_token)和更新令牌(refresh_token)
- 客户端持有访问令牌(access_token)和需要请求的参数向服务A发起资源请求,服务A拿着token去鉴权中心校验,无误后将资源返回给客户端
- 客户端访问受信任的服务B,发现服务B未授权,携带服务B的url去鉴权中心
- 去鉴权中心鉴权,发现该用户已经登录,token有效,重定向到服务B的redirect_uri,直接签发已有token,授权资源
10.客户端携带token 访问服务B
2. 代码相关
pom
-
鉴权中心
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-oauth2 -
服务A
与上面一直
配置
-
鉴权中心
标记为鉴权服务中心@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
// 令牌端点的安全约束 @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security // 允许表单登录 .allowFormAuthenticationForClients() // 公开token .tokenKeyAccess("permitAll()") // 全部允许验证token .checkTokenAccess("permitAll()"); } // 用内存存储 // 自动创建UserDetailsServiceInfo实例 @Autowired private UserDetailsServiceInfo userDetailsServiceInfo; // 自动加载WebSecurityConfig中的authenticationManagerBean()方法的返回值AuthenticationManager对象 @Autowired private AuthenticationManager authenticationManager; // 令牌端点配置 @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { super.configure(endpoints); // 认证管理器,密码模式时使用 endpoints.authenticationManager(this.authenticationManager) // 会自动调用UserDetailsServiceInfo下的loadUserByUsername()方法 .userDetailsService(this.userDetailsServiceInfo); } // 自动加载WebSecurityConfig中的bcryptPasswordEncoder()方法的返回值BCryptPasswordEncoder对象 @Autowired private PasswordEncoder bcryptPasswordEncoder; // 客户端信息配置 @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() // 客户端名称 .withClient("web") // 客户端密钥 .secret(this.bcryptPasswordEncoder.encode("123456")) // 设置授权模式为password .authorizedGrantTypes("password", "refresh_token") .scopes("all") // 设置token有效期 .accessTokenValiditySeconds(920) // 设置刷新token的有效期 .refreshTokenValiditySeconds(920) .autoApprove(true) .and() // 客户端名称 .withClient("app") // 客户端密钥 .secret(this.bcryptPasswordEncoder.encode("123456")) // 设置授权模式为password .authorizedGrantTypes("password", "authorization_code", "refresh_token") .scopes("all") // 设置token有效期 .accessTokenValiditySeconds(920) // 设置刷新token的有效期 .refreshTokenValiditySeconds(920) // 配置授权码模式必须配置uri,否则授权后跳转无权限 .redirectUris("http://127.0.0.1:8082/data/common") .autoApprove(true); }}
security,web启用
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// 用户权限管理器,进行用户认证,配置用户签名服务和用户权限控制
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
// 将BCryptPasswordEncoder对象注入Spring容器中,
// SpringSecurity会使用PasswordEncoder自动密码校验
@Bean
public PasswordEncoder bcryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
// 用户授权,配置拦截请求、请求验证、异常处理
@Override
protected void configure(HttpSecurity http) throws Exception {
//关闭csrf
http.csrf().disable();
// 解决跨域
http.cors();
// 开启Spring Security默认的表单登录
http.formLogin();
// 根据需求,自定义登录页面,注意不要拦截此Action
// .loginPage("/login");
// 设置认证的action
http.authorizeRequests()
// 不拦截以下action
.antMatchers("/sso/register").permitAll()
// 处了上面的action,都需要鉴权认证
.anyRequest().authenticated();
}
}
自定义认证过程
@Service
public class UserDetailsServiceInfo implements UserDetailsService {
// 自动加载WebSecurityConfig中的bcryptPasswordEncoder()方法的返回值BCryptPasswordEncoder对象
@Autowired
private PasswordEncoder bcryptPasswordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// (1)根据username查询数据库,找到账号和密码,下面类似查数据库
if (!"admin".equals(username)){
// 查不到数据返回null即可
return null;
}
// (2) 对查询的密码进行加密,如果数据库的密码已经加密,此处不做。
String password = this.bcryptPasswordEncoder.encode("123456");
// (3) 生成User对象
/*
// 使用userdetails自带的UserDetails的对象User
User user = new User("admin",password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin, secretary"));
return user;
*/
// 使用自定义的UserDetails对象UserDetailsInfo
UserDetailsInfo userDetailsInfo = new UserDetailsInfo("1","admin", password, null);
return userDetailsInfo;
}
}
-
服务A
标记为资源服务提供者@Configuration @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true) public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override public void configure(HttpSecurity http) throws Exception { //关闭csrf http.csrf().disable(); // 解决跨域 http.cors(); // 登录,此处可以不设置,默认会跳转到SpringSecurity的登录页面// http.formLogin();
// 设置认证的action http.authorizeRequests() // 不拦截以下action .antMatchers("/data/common") .permitAll() // 处了上面的action,都需要鉴权认证 .anyRequest().authenticated(); }}
yml
server:
port: 8082
security:
oauth2:
client:
# 配置授权服务器参数
client-id: web
client-secret: 123456
# 配置获取token
access-token-uri: http://127.0.0.1:8080/oauth/token
# 配置授权码模式认证,如果只有密码模式,此处可以不配置
# user-authorization-uri: http://127.0.0.1:8080/oauth/authorize
resource:
# 验证Token,并返回客户端信息
token-info-uri: http://127.0.0.1:8080/oauth/check_token
2. 验证流程
最终能获取到一个合法token,并且成功访问到资源
- 获取code
- 根据code获取token
- 携带token访问资源,成功
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
本文转自 jimolvxing.blog.csdn.net/article/det…,如有侵权,请联系删除。