SpringSecurity OAtu2+JWT實現(xiàn)微服務版本的單點登錄的示例
何為單點登錄
單點登錄通俗的話來講在微服務當中,在一個服務登錄后就能免去另一個服務的登錄操作,所謂單點登錄.
就好像你在微博總網站里登錄后,然后在微博里面的某一個模塊點進去后,就發(fā)現(xiàn)這個模塊竟然不用登錄了,不是因為這個模塊與主網站是一體的用一個SpringSecurity就可以搞定了,這里面的水深著呢!
感興趣更深這個SpringSecurity建議去看看圖靈課堂的SpringSecurity,建議不要看尚硅谷的,那個版本說實話感覺有點老式了,教你手寫,其實我覺得,你既然學到了這個層次了,就應該能建立起快速打通一個新技術的能力,這個"打通"的意思不是要你深入,而是會用!別想著深入,因為沒有什么實際意義,現(xiàn)在不是我們小白應該做的事,我們小白只要打好基礎就可以了,比如java,jvm,spring,mysql這些!
沒有SpringSecurity基礎就別看這篇文章了,你可能看得懂,但是你肯定實現(xiàn)不出來,不信我你就看
認證中心
新建一個微服務模塊,可以另外建項目,也可以直接在你微服務項目里建立模塊就可以了.
maven配置
? <dependencies> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.springframework.boot</groupId> ? ? ? ? ? ? <artifactId>spring-boot-starter-thymeleaf</artifactId> ? ? ? ? </dependency> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.springframework.boot</groupId> ? ? ? ? ? ? <artifactId>spring-boot-starter-web</artifactId> ? ? ? ? </dependency> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.springframework.cloud</groupId> ? ? ? ? ? ? <artifactId>spring-cloud-starter-oauth2</artifactId> ? ? ? ? </dependency> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.springframework.cloud</groupId> ? ? ? ? ? ? <artifactId>spring-cloud-starter-security</artifactId> ? ? ? ? </dependency> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.springframework.boot</groupId> ? ? ? ? ? ? <artifactId>spring-boot-starter-test</artifactId> ? ? ? ? ? ? <scope>test</scope> ? ? ? ? ? ? <exclusions> ? ? ? ? ? ? ? ? <exclusion> ? ? ? ? ? ? ? ? ? ? <groupId>org.junit.vintage</groupId> ? ? ? ? ? ? ? ? ? ? <artifactId>junit-vintage-engine</artifactId> ? ? ? ? ? ? ? ? </exclusion> ? ? ? ? ? ? </exclusions> ? ? ? ? </dependency> ? ? </dependencies>
用戶登錄邏輯
@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 tokenServices = (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;
? ? }
}配置規(guī)則中心
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 {
? ? ? ? // 將子系統(tǒng)的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);
? ? }
}請求模塊
下面這個是請求模塊,也就是獨立出一個微服務,假如這個微服務是做業(yè)務的,會給認證中心發(fā)出請求,然后去熱證,這個模塊也算登錄了.
那么有道友會問:其他模塊在該模塊登錄后還要登錄嗎?答案:不用!
至于要以什么為基礎,接著往下看:
請求模塊這個依賴很關鍵
? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.springframework.cloud</groupId> ? ? ? ? ? ? <artifactId>spring-cloud-starter-oauth2</artifactId> ? ? ? ? </dependency> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.springframework.cloud</groupId> ? ? ? ? ? ? <artifactId>spring-cloud-starter-security</artifactId> ? ? ? ? </dependency>
這個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();
? ? }
}真實請求
下面就可以正式去請求了,這里很多網友都會有疑問,就是前面我在認證中心授予了權限之后,在其他模塊該如何去權限的規(guī)定呢?其實很簡單,有很多博主都沒有說,直接加上注解就可以了.
? ? @GetMapping("/get")
? ? @PreAuthorize("hasAuthority('ROLE_NORMAL')")
? ? public String get(HttpServletRequest request){
? ? ? ? System.out.println("函數(shù)進來了");
? ? ? ? return "uusb1j";
? ? }
}這個時候,如果該微服務的get請求過來,就會跳轉到認證中心去認證.
一些小問題
這個時候只要有相同配置的模塊都不用自行登錄了.如果有一個模塊進行登出請求,所有服務都會進行登出.
注意認證中心有項配置redirectUris(“http://192.168.216.1:8001/login”,“http://192.168.216.1:8004/login”),這個配置代表認證成功后重定向去哪個地址,但并不會真的重定向去對應模塊的login頁,而是重定向去你請求前被攔截的地址,但是這個有講究就是必須配置請求前所在模塊的地址,每個模塊對應一個重定向地址,最好是重定向到對應模塊的/login頁,其他頁也行.如果你從網關過來,然后你這里重定向回網關是不行的,除非你網關有相關操作,不然你網關只是一個轉發(fā)功能,是先轉發(fā)到對應模塊,然后發(fā)現(xiàn)該模塊的某個地址不可訪問,才去認證中心請求權限的,所以這里的重定向地址還是具體到對應模塊才對,其他不行,有多個用","隔開就行.
到此這篇關于SpringSecurity OAtu2+JWT實現(xiàn)微服務版本的單點登錄的示例的文章就介紹到這了,更多相關SpringSecurity OAtu2 JWT單點登錄內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決springboot自定義注解AOP在controller上導致controller注入失敗問題
這篇文章主要介紹了解決springboot自定義注解AOP在controller上導致controller注入失敗問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
Java根據(jù)實體生成SQL數(shù)據(jù)庫表的示例代碼
這篇文章主要來和大家分享一個Java實現(xiàn)根據(jù)實體生成SQL數(shù)據(jù)庫表的代碼,文中的實現(xiàn)代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2023-07-07
高效數(shù)據(jù)傳輸?shù)拿孛芪淦鱌rotobuf的使用教程
Protobuf(Protocol?Buffers)是由?Google?開發(fā)的一種輕量級、高效的數(shù)據(jù)交換格式,它被用于結構化數(shù)據(jù)的序列化、反序列化和傳輸,本文主要介紹了它的具體使用方法,需要的可以參考一下2023-05-05

