赞
踩
提示:以下是本篇文章正文内容,下面案例可供参考
Client: 客户端,也就是Third-party application - 第三方应用程序
Service:服务端,也就是服务的提供者
User: 用户,也就是Resource Owner - 资源所有者
User Agent:用户代理,如浏览器,下文中将其与Client合并考虑。
Authorization Server:认证服务器,即服务提供商专门用来处理认证的服务器。
Resource Server:资源服务器,即服务提供商存放用户生成的资源的服务器。
`AuthorizationServer 授权服务接口介绍`
/oauth/authorize: 验证接口, AuthorizationEndpoint
/oauth/token: 获取token
/oauth/confirm_access:用户授权
/oauth/error: 认证失败
/oauth/check_token: 资源服务器用来校验token
/oauth/token_key: jwt模式下获取公钥;位于:TokenKeyEndpoint ,通过 JwtAccessTokenConverter 访问key
`规范`
JWT – Json Web Token, 如其名,使用Json方式保存Web Token的协议。
网上有各种解读,个人理解,这就是一个 客户端Session - Session保存在客户端,而不是通常的保存在服务端。
`构成`
JWT三部分组成:
Header 头部:JSON方式描述JWT基本信息,如类型和签名算法。使用Base64编码为字符串
Payload 载荷:JSON方式描述JWT信息,除了标准定义的,还可以添加自定义的信息。同样使用Base64编码为字符串。
i
ss: 签发者
sub: 用户
aud: 接收方
exp(expires): unix时间戳描述的过期时间
iat(issued at): unix时间戳描述的签发时间
Signature 签名:将前两个字符串用 . 连接后,使用头部定义的加密算法,利用密钥进行签名,并将签名信息附在最后。
授权码模式(authorization code)
简化模式(implicit)
密码模式(resource owner password credentials)
客户端模式(client credentials)
配置资源服务器
配置授权认证服务器
配置security web
AuthorizationServerConfig.java
import lombok.AllArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import java.util.Arrays; /** * @Author: cw * @Date: 2020/12/24 15:28 * @Description: 授权服务器配置 */ @Configuration @EnableAuthorizationServer @AllArgsConstructor public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { // 令牌持久化配置 private final TokenStore tokenStore; // 客户端详情服务 private final ClientDetailsService clientDetailsService; // 认证管理器 private final AuthenticationManager authenticationManager; // 授权码服务 private final AuthorizationCodeServices authorizationCodeServices; // jwtToken解析器 private final JwtAccessTokenConverter jwtAccessTokenConverter; /** * 客户端详情服务配置 (demo采用本地内存存储) */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.// 使用本地内存存储 inMemory() // 客户端id .withClient("client_1") // 客户端密码 .secret(new BCryptPasswordEncoder().encode("123456")) // 该客户端允许授权的类型 .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token") // 该客户端允许授权的范围 .scopes("all") // false跳转到授权页面,true不跳转,直接发令牌 .autoApprove(false); // 配置两个客户端,一个用于password认证一个用于client认证 // String finalSecret = "{bcrypt}" + new BCryptPasswordEncoder().encode("123456"); // clients.inMemory().withClient("client_1") // .resourceIds("testId") // // 认证方式 client 认证 // .authorizedGrantTypes("client_credentials", "refresh_token") // .scopes("select") // .authorities("oauth2") // .secret(finalSecret) // .and().withClient("client_2") // .resourceIds("testId") // // 认证方式 密码 认证 // .authorizedGrantTypes("password", "refresh_token") // .scopes("server") // .authorities("oauth2") // .secret(finalSecret); } /** * 配置访问令牌端点 */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints // 认证管理器 .authenticationManager(authenticationManager) // 授权码服务 .authorizationCodeServices(authorizationCodeServices) // 令牌管理服务 .tokenServices(tokenServices()) .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); } /** * 配置令牌端点安全约束 */ @Override public void configure(AuthorizationServerSecurityConfigurer security) { security // oauth/check_token公开 .checkTokenAccess("permitAll()") // oauth/token_key 公开密钥 .tokenKeyAccess("permitAll()") // 允许表单认证 .allowFormAuthenticationForClients(); } /** * 令牌服务配置 * * @return 令牌服务对象 */ public AuthorizationServerTokenServices tokenServices() { DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setTokenStore(tokenStore); tokenServices.setSupportRefreshToken(true); // 令牌增强 TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter)); tokenServices.setTokenEnhancer(tokenEnhancerChain); // 令牌默认有效期2小时 tokenServices.setAccessTokenValiditySeconds(60 * 60 * 2); // 刷新令牌默认有效期3天 tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 3); return tokenServices; } }
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.provisioning.InMemoryUserDetailsManager; /** * @Author: cw * @Date: 2020/12/24 15:07 * @Description: Security 安全配置 */ @EnableWebSecurity @Configuration public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { /** * 安全拦截机制 */ @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() // 放行 .antMatchers("/auth/**") .permitAll() // 其他请求必须认证通过 .anyRequest().authenticated() .and() .formLogin() // 允许表单登录 // .successForwardUrl("/login-success") //自定义登录成功跳转页 .and() .csrf().disable(); } /** * token持久化配置 */ @Bean public TokenStore tokenStore() { // 本地内存存储令牌 return new InMemoryTokenStore(); } /** * 密码加密器 * @return */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } /** * 认证管理器配置 * * 不定义没有 password grant_type,密码模式需要AuthenticationManager支持 * @return * @throws Exception */ @Bean @Override protected AuthenticationManager authenticationManager() { return authentication -> daoAuthenticationProvider().authenticate(authentication); } /** * 认证是由 AuthenticationManager 来管理的, * 但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider, * 用于调用userDetailsService进行验证 */ @Bean public AuthenticationProvider daoAuthenticationProvider() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setUserDetailsService(userDetailsService()); daoAuthenticationProvider.setHideUserNotFoundExceptions(false); daoAuthenticationProvider.setPasswordEncoder(passwordEncoder()); return daoAuthenticationProvider; } /** * 用户详情服务 */ @Bean @Override protected UserDetailsService userDetailsService() { // 测试方便采用内存存取方式 InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager(); userDetailsService.createUser(User.withUsername("user_1").password(passwordEncoder().encode("123456")).authorities("ROLE_USER").build()); userDetailsService.createUser(User.withUsername("user_2").password(passwordEncoder().encode("1234567")).authorities("ROLE_USER").build()); return userDetailsService; } /** * 设置授权码模式的授权码如何存取,暂时采用内存方式 */ @Bean public AuthorizationCodeServices authorizationCodeServices() { return new InMemoryAuthorizationCodeServices(); } /** * jwt token解析器 */ @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); // 对称密钥,资源服务器使用该密钥来验证 converter.setSigningKey("JoNyCw"); return converter; } }
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.RemoteTokenServices; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; 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; /** * @Author: cw * @Date: 2020/12/24 15:33 * @Description: 资源服务器配置 */ @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { /** * 配置资源访问的令牌方式 * @param resources * @throws Exception */ @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.tokenServices(tokenServices()); } /** * 路由安全认证配置 */ @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 配置hello打头的路由需要安全认证 .antMatchers("/hello/**") .authenticated() .and().csrf().disable(); } /** * 资源服务令牌解析服务 */ @Bean @Primary public ResourceServerTokenServices tokenServices() { RemoteTokenServices remoteTokenServices = new RemoteTokenServices(); remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:8085/oauth/check_token"); remoteTokenServices.setClientId("client_1"); remoteTokenServices.setClientSecret("123456"); return remoteTokenServices; } /** * jwt token 校验解析器 */ @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter()); } /** * Token转换器必须与认证服务一致 */ @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("JoNyCw"); return accessTokenConverter; } }
待补充 网关聚合下统一授权
github:https://github.com/jonycw/spring-cloud-demo.git
参考:
https://www.jianshu.com/p/3427549a148a
https://www.cnblogs.com/yoci/p/13203215.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。