日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring MVC实现Spring Security,Spring Stomp websocket Jetty嵌入式运行

發(fā)布時間:2025/3/21 javascript 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring MVC实现Spring Security,Spring Stomp websocket Jetty嵌入式运行 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
使用Spring框架各個組件實現(xiàn)一個在線聊天網(wǎng)頁,當(dāng)有用戶連接WebSocket,服務(wù)器監(jiān)聽到用戶連接會使用Stomp推送最新用戶列表,有用戶斷開刷新在線列表,實時推送用戶聊天信息。引入Jetty服務(wù)器,直接嵌入整個工程可以脫離Java Web容器獨立運行,使用插件打包成一個jar文件,就像Spring Boot一樣運行,部署。

pom.xml 依賴

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><maven.compiler.encoding>UTF-8</maven.compiler.encoding><jetty.version>9.4.8.v20171121</jetty.version><spring.version>5.0.4.RELEASE</spring.version><jackson.version>2.9.4</jackson.version><lombok.version>1.16.18</lombok.version><dbh2.version>1.4.196</dbh2.version><jcl.slf4j.version>1.7.25</jcl.slf4j.version><spring.security.version>5.0.3.RELEASE</spring.security.version><logback.version>1.2.3</logback.version><activemq.version>5.15.0</activemq.version></properties><dependencies><dependency><groupId>org.eclipse.jetty</groupId><artifactId>jetty-servlet</artifactId><version>${jetty.version}</version></dependency><!-- 添加websocket 依賴不然會出現(xiàn) java.lang.IllegalStateException: No suitable defaultRequestUpgradeStrategy found --><dependency><groupId>org.eclipse.jetty.websocket</groupId><artifactId>websocket-server</artifactId><version>${jetty.version}</version></dependency><dependency><groupId>org.eclipse.jetty.websocket</groupId><artifactId>websocket-api</artifactId><version>${jetty.version}</version></dependency><!--spring mvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webflux</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-messaging</artifactId><version>${spring.version}</version></dependency><!--spring security --><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-web</artifactId><version>${spring.security.version}</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-config</artifactId><version>${spring.security.version}</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-oauth2-client</artifactId><version>${spring.security.version}</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-oauth2-jose</artifactId><version>${spring.security.version}</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-messaging</artifactId><version>${spring.security.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>${jackson.version}</version></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><version>${dbh2.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>${jackson.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>${jcl.slf4j.version}</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>${logback.version}</version></dependency><dependency><groupId>org.apache.activemq</groupId><artifactId>activemq-broker</artifactId><version>${activemq.version}</version></dependency><dependency><groupId>io.projectreactor.ipc</groupId><artifactId>reactor-netty</artifactId><version>0.7.2.RELEASE</version></dependency></dependencies>

1. 配置H2 嵌入式數(shù)據(jù)庫

@Bean //內(nèi)存模式public DataSource dataSource(){EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();EmbeddedDatabase build = builder.setType(EmbeddedDatabaseType.H2).addScript("db/sql/create-db.sql") //每次創(chuàng)建數(shù)據(jù)源都會執(zhí)行腳本.addScript("db/sql/insert-data.sql").build();return build;}

這種方式是利用Spring 內(nèi)置的嵌入式數(shù)據(jù)庫的數(shù)據(jù)源模板,創(chuàng)建的數(shù)據(jù)源,比較簡單,但是這種方式不支持定制,數(shù)據(jù)只能保存在內(nèi)存中,項目重啟數(shù)據(jù)就會丟失了。

設(shè)置數(shù)據(jù)保存到硬盤

@Beanpublic DataSource dataSource() {DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName("org.h2.Driver");dataSource.setUsername("embedded");dataSource.setPassword("embedded");dataSource.setUrl("jdbc:h2:file:./data;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false;");return dataSource;}

如果你還想每次創(chuàng)建數(shù)據(jù)源執(zhí)行初始化sql,使用org.springframework.jdbc.datasource.init.ResourceDatabasePopulator 裝載sql 腳本用于初始化或清理數(shù)據(jù)庫

@Beanpublic ResourceDatabasePopulator databasePopulator() {ResourceDatabasePopulator populator = new ResourceDatabasePopulator();populator.addScript(schema);populator.addScripts(data);populator.setContinueOnError(true);return populator;}

設(shè)置DatabasePopulator 對象,用戶數(shù)據(jù)源啟動或者消耗的時候執(zhí)行腳本

@Beanpublic DataSourceInitializer initializer() {DataSourceInitializer initializer = new DataSourceInitializer();initializer.setDatabasePopulator(databasePopulator());initializer.setDataSource(dataSource());return initializer;}

啟用H2 web Console

@Bean(initMethod = "start",destroyMethod = "stop")public Server DatasourcesManager() throws SQLException {return Server.createWebServer("-web","-webAllowOthers","-webPort","8082");}

瀏覽器打開 http://localhost:8082 訪問H2 控制臺

設(shè)置事務(wù)管理器

@Beanpublic PlatformTransactionManager transactionManager() {PlatformTransactionManager manager = new DataSourceTransactionManager(dataSource());return manager;} }

到這里,嵌入H2數(shù)據(jù)庫配置基本已經(jīng)設(shè)置完成了

2. Spring MVC配置

import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;@Configuration @EnableWebMvc @ComponentScan(basePackages = "org.ting.spring.controller", //基包路徑設(shè)置includeFilters = @ComponentScan.Filter(value = {ControllerAdvice.class,Controller.class})) //只掃描MVC controll的注解 public class WebMvcConfiguration implements WebMvcConfigurer {public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(new MappingJackson2HttpMessageConverter());}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {//添加靜態(tài)路徑映射registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");} }

3. Jetty嵌入式服務(wù)

因為Spring 注解掃描只能注冊一個類, 使用@Import引入其他的配置類

@Configuration @ComponentScan(basePackages = "org.ting.spring",excludeFilters = {@ComponentScan.Filter(value = {Controller.class,ControllerAdvice.class})}) @Import({WebMvcConfiguration.class}) //引入Spring MVC配置類 public class WebRootConfiguration {@Autowiredprivate DataSource dataSource;@Beanpublic JdbcTemplate jdbcTemplate(){JdbcTemplate template = new JdbcTemplate(dataSource);return template;} }

使用Spring AnnotationConfigWebApplicationContext 啟動注解掃描,注冊創(chuàng)建bean將WebApplicationContext,在將對象傳給DispatcherServlet

public class JettyEmbedServer {private final static int DEFAULT_PORT = 9999;private final static String DEFAULT_CONTEXT_PATH = "/";private final static String MAPPING_URL = "/*";public static void main(String[] args) throws Exception {Server server = new Server(DEFAULT_PORT);JettyEmbedServer helloServer = new JettyEmbedServer();server.setHandler(helloServer.servletContextHandler());server.start();server.join();}private ServletContextHandler servletContextHandler() {WebApplicationContext context = webApplicationContext();ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);servletContextHandler.setContextPath(DEFAULT_CONTEXT_PATH);ServletHolder servletHolder = new ServletHolder(new DispatcherServlet(context));servletHolder.setAsyncSupported(true);servletContextHandler.addServlet(servletHolder, MAPPING_URL);return servletContextHandler;}private WebApplicationContext webApplicationContext() {AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();context.register(WebRootConfiguration.class);return context;}

3. 配置Spring Security

默認(rèn)Spring Security攔截請求,登錄失敗,登錄成功都是頁面跳轉(zhuǎn)的方式,我們希望ajax請求的時候,無論是被攔截了,或者登錄失敗,成功都可以返回json格式數(shù)據(jù),由前端人員來處理。
根據(jù)HttpRequestServlet 請求頭 X-Requested-With是否等于XMLHttpRequest 判斷是否是ajax。

public class RespnonseJson {public static void jsonType(HttpServletResponse response) {response.setContentType("application/json;charset=UTF-8");response.setCharacterEncoding("utf-8");}public static boolean ajaxRequest(HttpServletRequest request){String header = request.getHeader("X-Requested-With");return ! StringUtils.isEmpty(header) && header.equals("XMLHttpRequest");}public static boolean matchURL(String url) {Pattern compile = Pattern.compile("^/api/.+");return compile.matcher(url).matches();} }

登錄認(rèn)證處理器

public class RestAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {/*** @param loginFormUrl URL where the login page can be found. Should either be* relative to the web-app context path (include a leading {@code /}) or an absolute* URL.*/public RestAuthenticationEntryPoint(String loginFormUrl) {super(loginFormUrl);}@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {String uri = request.getRequestURI();if (matchURL(uri)) { // /api 都是ajax 請求jsonType(response);response.getWriter().println(getErr(authException.getMessage()));}else if (ajaxRequest(request)){jsonType(response);response.getWriter().println(getErr(authException.getMessage()));}else super.commence(request,response,authException);}private String getErr(String description) throws JsonProcessingException {Result result = Result.error(Result.HTTP_FORBIDDEN, description);ObjectMapper mapper = new ObjectMapper();return mapper.writeValueAsString(result);} }

登錄成功處理

public class RestAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {String uri = request.getRequestURI();if (matchURL(uri)){jsonType(response);String value = loginSuccess();response.getWriter().println(value);}else if (ajaxRequest(request)){jsonType(response);String success = loginSuccess();response.getWriter().println(success);}else super.onAuthenticationSuccess(request,response,authentication);}private String loginSuccess() throws JsonProcessingException {Result success = Result.success("sign on success go to next!");ObjectMapper mapper = new ObjectMapper();return mapper.writeValueAsString(success);} }

登錄失敗處理

public class RestAuthFailureHandler extends SimpleUrlAuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {if (ajaxRequest(request)){jsonType(response);String err = getErr(exception.getMessage());response.getWriter().println(err);}else super.onAuthenticationFailure(request,response,exception);}public String getErr(String description) throws JsonProcessingException {Result result = Result.error(Result.HTTP_AUTH_FAILURE, description);ObjectMapper mapper = new ObjectMapper();return mapper.writeValueAsString(result);} }

我在網(wǎng)上搜索ajax 認(rèn)證錯誤,很多博客是這樣寫的

response.sendError(500, "Authentication failed");

這個錯誤會被Jetty 錯誤頁面捕獲,擾亂返回JSON數(shù)據(jù),這個細(xì)節(jié)要注意下

注冊Handler

@Beanpublic AuthenticationEntryPoint entryPoint() {RestAuthenticationEntryPoint entryPoint = new RestAuthenticationEntryPoint("/static/html/login.html"); return entryPoint;}@Beanpublic SimpleUrlAuthenticationSuccessHandler successHandler() {RestAuthSuccessHandler successHandler = new RestAuthSuccessHandler();return successHandler;}@Beanpublic SimpleUrlAuthenticationFailureHandler failureHandler() {RestAuthFailureHandler failureHandler = new RestAuthFailureHandler();return failureHandler;}

配置url 認(rèn)證

@Beanpublic SessionRegistry sessionManager() {return new SessionRegistryImpl();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.exceptionHandling().authenticationEntryPoint(entryPoint()).and().authorizeRequests().antMatchers("/static/html/jetty-chat.html","/api/user/online", "/api/user/loginuser") .authenticated() //設(shè)置需要認(rèn)證才可以請求的接口.and().formLogin().successHandler(successHandler()) //登錄成功處理.failureHandler(failureHandler()) //登錄失敗處理.loginPage("/static/html/login.html") //登錄頁面.loginProcessingUrl("/auth/login") //登錄表單url .defaultSuccessUrl("/static/html/jetty-chat.html") //成功跳轉(zhuǎn)url.permitAll().and().csrf().disable()//禁用csrf 因為沒有使用模板引擎.sessionManagement().maximumSessions(1) //設(shè)置同一個賬戶,同時在線次數(shù).sessionRegistry(sessionManager()) // 設(shè)置Session 管理器,.expiredUrl("/static/html/login.html") //session 失效后,跳轉(zhuǎn)url.maxSessionsPreventsLogin(false) //設(shè)置true,達(dá)到session 最大登錄次數(shù)后,后面的賬戶都會登錄失敗,false 頂號 前面登錄賬戶會被后面頂下線;//注銷賬戶,跳轉(zhuǎn)到登錄頁面http.logout().logoutUrl("/logout").logoutSuccessUrl("/static/html/login.html");

在配置類添加@EnableWebSecurity,在掃描類上引入Spring Security配置,大功告成了,并沒有!Spring Security 是使用Filter來處理一些認(rèn)證請求,需要我們在Jetty中手動注冊攔截器

//手動注冊攔截器,讓Spring Security 生效FilterHolder filterHolder = new FilterHolder(new DelegatingFilterProxy("springSecurityFilterChain"));servletContextHandler.addFilter(filterHolder, MAPPING_URL, null);servletContextHandler.addEventListener(new ContextLoaderListener(context));servletContextHandler.addEventListener(new HttpSessionEventPublisher()); //使用security session 監(jiān)聽器 限制只允許一個用戶登錄

4. 配置WebSocketStompConfig

@Configuration @EnableWebSocketMessageBroker @ComponentScan(basePackages = "org.ting.spring.stomp.message") @Slf4j public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {//設(shè)置連接的端點路徑@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("endpoint").withSockJS();}@Overridepublic void configureMessageBroker(MessageBrokerRegistry registry) {// 定義了兩個客戶端訂閱地址的前綴信息,也就是客戶端接收服務(wù)端發(fā)送消息的前綴信息registry.enableSimpleBroker("/topic", "/queue");// 定義了服務(wù)端接收地址的前綴,也即客戶端給服務(wù)端發(fā)消息的地址前綴registry.setApplicationDestinationPrefixes("/app");//使用客戶端一對一通信registry.setUserDestinationPrefix("/user");registry.setPathMatcher(new AntPathMatcher("."));}}

配置stomp 頻道認(rèn)證

@Configuration public class SocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {@Overrideprotected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {messages.simpDestMatchers("/user/**").authenticated()//認(rèn)證所有user 鏈接.anyMessage().permitAll();}//允許跨域 不然會出現(xiàn) Could not verify the provided CSRF token because your session was not found 異常@Overrideprotected boolean sameOriginDisabled() {return true;} }

信息處理

@Controller @Slf4j public class StompController {@Autowiredprivate SimpMessagingTemplate messagingTemplate;@MessageExceptionHandler@SendToUser("/queue.errors")public String handleException(Throwable exception) {return exception.getMessage();}@MessageMapping("receive.messgae")public void forwardMsg(ChatMessage message){log.info("message : {}",message);message.setLocalDateTime(LocalDateTime.now());messagingTemplate.convertAndSendToUser(message.getTargetUser().getEmail(),"queue.notification",message);}}

@MessageMapping 作用與@RequestMapping 功能差不多用于匹配url
更多Spring WebSocket 官方文檔查看

我們使用一個集合來保存連接上的用戶,使用連接,斷開監(jiān)聽器來修改集合的列表,并將集合的數(shù)據(jù)發(fā)布到頻道上。

websocket 斷開連接監(jiān)聽器

@Component @Slf4j public class WebSocketDisconnectListener implements ApplicationListener<SessionDisconnectEvent> {@Autowiredprivate UserService userService;@Autowiredprivate SimpMessagingTemplate messageTemplate;@Overridepublic void onApplicationEvent(SessionDisconnectEvent event) {Principal principal = event.getUser();log.info("client sessionId : {} name : {} disconnect ....",event.getSessionId(),principal.getName());if (principal != null){ //已經(jīng)認(rèn)證過的用戶User user = userService.findByEmail(principal.getName());Online.remove(user);messageTemplate.convertAndSend("/topic/user.list",Online.onlineUsers());}} }

注冊連接websocket 監(jiān)聽器

@Component @Slf4j public class WebSocketSessionConnectEvent implements ApplicationListener<SessionConnectEvent>{@Autowiredprivate SimpMessagingTemplate messageTemplate;@Autowiredprivate UserService userService;@Overridepublic void onApplicationEvent(SessionConnectEvent event) {Principal principal = event.getUser();log.info("client name: {} connect.....",principal.getName());if (principal != null){User user = userService.findByEmail(principal.getName());Online.add(user);messageTemplate.convertAndSend("/topic/user.list",Online.onlineUsers());}} }

保存在線列表

public class Online {private static Map<String,User> maps = new ConcurrentHashMap<>();public static void add(User user){maps.put(user.getEmail(),user);}public static void remove(User user){maps.remove(user.getEmail());}public static Collection<User> onlineUsers(){return maps.values();}}

4. Spring Security OAuth2 Client 配置

手動配置ClientRegistrationRepository 設(shè)置client-id,client-secret,redirect-uri-template

@Beanpublic ClientRegistrationRepository clientRegistrationRepository() {return new InMemoryClientRegistrationRepository(githubClientRegstrationRepository(),googleClientRegistrionRepository());}public ClientRegistration githubClientRegstrationRepository(){return CommonOAuth2Provider.GITHUB.getBuilder("github").clientId(env.getProperty("registration.github.client-id")).clientSecret(env.getProperty("registration.github.client-secret")).redirectUriTemplate(env.getProperty("registration.github.redirect-uri-template")).build();}public ClientRegistration googleClientRegistrionRepository(){return CommonOAuth2Provider.GOOGLE.getBuilder("google").clientId(env.getProperty("registration.google.client-id")).clientSecret(env.getProperty("registration.google.client-secret")).redirectUriTemplate(env.getProperty("registration.google.redirect-uri-template")).scope( "profile", "email").build();}@Beanpublic OAuth2AuthorizedClientService authorizedClientService() {return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository());}

我們使用github,google OAuth2 授權(quán)登錄的賬戶,登錄通過后保存起來,則需求繼承DefaultOAuth2UserService

@Service @Slf4j public class CustomOAuth2UserService extends DefaultOAuth2UserService {@Autowiredprivate UserService userService;@Overridepublic OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {OAuth2User oAuth2User = super.loadUser(userRequest);try {oAuth2User = processOAuth2User(oAuth2User,userRequest);} catch (Exception e) {log.error("processOAuth2User error {}",e);}return oAuth2User;}private OAuth2User processOAuth2User(OAuth2User oAuth2User,OAuth2UserRequest userRequest) {String clientId = userRequest.getClientRegistration().getRegistrationId();if (clientId.equalsIgnoreCase("github")) {Map<String, Object> map = oAuth2User.getAttributes();String login = map.get("login")+"_oauth_github";String name = (String) map.get("name");String avatarUrl = (String) map.get("avatar_url");User user = userService.findByEmail(login);if (user == null) {user = new User();user.setUsername(name);user.setEmail(login);user.setAvatar(avatarUrl);user.setPassword("123456");userService.insert(user);}else {user.setUsername(name);user.setAvatar(avatarUrl);userService.update(user);}return UserPrincipal.create(user, oAuth2User.getAttributes());}else if (clientId.equalsIgnoreCase("google")){Map<String, Object> result = oAuth2User.getAttributes();String email = result.get("email")+"_oauth_google";String username = (String) result.get("name");String imgUrl = (String) result.get("picture");User user = userService.findByEmail(email);if (user == null){user = new User();user.setEmail(email);user.setPassword("123456");user.setAvatar(imgUrl);user.setUsername(username);userService.insert(user);}else {user.setUsername(username);user.setAvatar(imgUrl);userService.update(user);}return UserPrincipal.create(user,oAuth2User.getAttributes());}return null;} }

重寫UserDetails

public class UserPrincipal implements OAuth2User,UserDetails {private long id;private String name;private String password;private boolean enable;private Collection<? extends GrantedAuthority> authorities;private Map<String,Object> attributes;UserPrincipal(long id,String name,String password,boolean enable,Collection<? extends GrantedAuthority> authorities){this.id = id;this.name = name;this.password = password;this.authorities = authorities;this.enable = enable;}public static UserPrincipal create(User user){return new UserPrincipal(user.getId(),user.getEmail(),user.getPassword(),user.isEnable(),Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));}public static UserPrincipal create(User user, Map<String, Object> attributes) {UserPrincipal userPrincipal = UserPrincipal.create(user);userPrincipal.attributes = attributes;return userPrincipal;}@Overridepublic String getPassword() {return this.password;}@Overridepublic String getUsername() {return name;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return this.enable;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return this.authorities;}@Overridepublic Map<String, Object> getAttributes() {return this.attributes;}@Overridepublic String getName() {return String.valueOf(this.id);} }

設(shè)置Spring Security OAuth2 Client

@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate CustomOAuth2UserService customOAuth2UserService;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.oauth2Login().clientRegistrationRepository(clientRegistrationRepository()).authorizedClientService(authorizedClientService()).userInfoEndpoint().userService(customOAuth2UserService).and().defaultSuccessUrl("/static/html/jetty-chat.html"); } }

默認(rèn)授權(quán)端點,點擊后直接重定向到授權(quán)服務(wù)器的登錄頁面,Spring 默認(rèn)是: oauth2/authorization/{clientId}
默認(rèn)授權(quán)成功跳轉(zhuǎn)url: /login/oauth2/code/{clientId}

這個項目參考的教程:
https://www.baeldung.com/spring-security-5-oauth2-login
https://www.callicoder.com/spring-boot-security-oauth2-social-login-part-1/

這個教程只展示了一部分的代碼,想查看完整的項目代碼,可以去github: spring-stomp-security-webflux-embedded-jetty查看

總結(jié)

以上是生活随笔為你收集整理的Spring MVC实现Spring Security,Spring Stomp websocket Jetty嵌入式运行的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。