Java设计模式之外观模式示例详解
267
2022-07-28
目录何为单点登录认证中心maven配置用户登录逻辑OAtuh2配置配置服务中心配置规则中心请求模块真实请求一些小问题
何为单点登录
单点登录通俗的话来讲在微服务当中,在一个服务登录后就能免去另一个服务的登录操作,所谓单点登录.
就好像你在微博总网站里登录后,然后在微博里面的某一个模块点进去后,就发现这个模块竟然不用登录了,不是因为这个模块与主网站是一体的用一个SpringSecurity就可以搞定了,这里面的水深着呢!感兴趣更深这个SpringSecurity建议去看看图灵课堂的SpringSecurity,建议不要看尚硅谷的,那个版本说实话感觉有点老式了,教你手写,其实我觉得,你既然学到了这个层次了,就应该能建立起快速打通一个新技术的能力,这个"打通"的意思不是要你深入,而是会用!别想着深入,因为没有什么实际意义,现在不是我们小白应该做的事,我们小白只要打好基础就可以了,比如java,jvm,spring,mysql这些!没有SpringSecurity基础就别看这篇文章了,你可能看得懂,但是你肯定实现不出来,不信我你就看
认证中心
新建一个微服务模块,可以另外建项目,也可以直接在你微服务项目里建立模块就可以了.
maven配置
用户登录逻辑
@Component
public class SheepUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
if( !"admin".equals(s) )
throw new UsernameNotFoundException("用户" + s + "不存在" );
return new User( s, passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_NORMAL,ROLE_MEDIUM"));
}
}
OAtuh2配置
配置服务中心
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
SheepUserDetailsService sheepUserDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 定义了两个客户端应用的通行证
clients.inMemory()
.withClient("admin")
.secret(new BCryptPasswordEncoder().encode("123456"))
.authorizedGrantTypes("authorization_code", "refresh_token","password")
.scopes("all")
.autoApprove(true)
.redirectUris("http://192.168.216.1:8001/login","http://192.168.216.1:8004/login");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter());
DefaultTokenServices thttp://okenServices = (DefaultTokenServices) endpoints.getDefaultAuthorizationServerTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(1)); // 一天有效期
endpoints.tokenServices(tokenServices);
//密码模式配置
endpoints.authenticationManager(authenticationManager).userDetailsService(sheepUserDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("isAuthenticated()")
.checkTokenAccess("permitAll()")
.allowFormAuthenticationForClients();
}
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("testKey");
return converter;
}
}
配置规则中心
Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setHideUserNotFoundExceptions(false);
return authenticationProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**","/uac/oauth/token","/remove")
.and()
.authorizeRequests()
.antMatchers("/oauth/**").authenticated()
.and()
.formLogin().permitAll()
.and()
.logout()
.logoutSuccessHandler(customLogoutSuccessHandler)
// 无效会话
.invalidateHttpSession(true)
// 清除身份验证
.clearAuthentication(true)
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
}
@Component
public class CustomLogoutSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// 将子系统的cookie删掉
//建议将token也删除,直接写个controller接口就可以了,可以在前端调用/logout的同时调用删除token接口
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length>0){
for (Cookie cookie : cookies){
cookie.setMaxAge(0);
cookie.setPath("/");
response.addCookie(cookie);
}
}
super.handle(request, response, authentication);
}
}
请求模块
下面这个是请求模块,也就是独立出一个微服务,假如这个微服务是做业务的,会给认证中心发出请求,然后去热证,这个模块也算登录了.那么有道友会问:其他模块在该模块登录后还要登录吗?答案:不用!至于要以什么为基础,接着往下看:
请求模块这个依赖很关键
这个yml也很重要
auth-server: http://localhost:8085/uac
security:
oauth2:
client:
client-id: admin
client-secret: 123456
user-authorization-uri: ${auth-server}/oauth/authorize #认证
access-token-uri: ${auth-server}/oauth/token #获取token
resource:
jwt:
key-uri: ${auth-server}/oauth/token_key #忘了,反正要写上
上面的认证和获取token这两个配置很重要,还有一个/oauth/check_token,这个是用来检查token是否合法的,这些都怎么用,是什么,后面会说
下面这个也很重要
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableOAuth2Sso
public class ClientWebsecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
//下面表示该模块所有请求都要拦截
//因为在yml配置了认证中心的各个路径,所以会自动跳转到认证中心去认证
//如果你想在当前模块排除哪些拦截,可以在下面去排除
http.antMatcher("/**").authorizeRequests()
.anyRequest().authenticated();
}
}
真实请求
下面就可以正式去请求了,这里很多网友都会有疑问,就是前面我在认证中心授予了权限之后,在其他模块该如何去权限的规定呢?其实很简单,有很多博主都没有说,直接加上注解就可以了.
@GetMapping("/get")
@PreAuthorize("hasAuthority('ROLE_NORMAL')")
public String get(HttpServletRequest request){
System.out.println("函数进来了");
return "uusb1j";
}
}
这个时候,如果该微服务的get请求过来,就会跳转到认证中心去认证.
一些小问题
这个时候只要有相同配置的模块都不用自行登录了.如果有一个模块进行登出请求,所有服务都会进行登出.
注意认证中心有项配置redirectUris(“http://192.168.216.1:8001/login”,“http://192.168.216.1:8004/login”),这个配置代表认证成功后重定向去哪个地址,但并不会真的重定向去对应模块的login页,而是重定向去你请求前被拦截的地址,但是这个有讲究就是必须配置请求前所在模块的地址,每个模块对应一个重定向地址,最好是重定向到对应模块的/login页,其他页也行.如果你从网关过来,然后你这里重定向回网关是不行的,除非你网关有相关操作,不然你网关只是一个转发功能,是先转发到对应模块,然后发现该模块的某个地址不可访问,才去认证中心请求权限的,所以这里的重定向地址还是具体到对应模块才对,其他不行,有多个用","隔开就行.
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~