当前位置: 首页 > news >正文

有关外贸的网站有哪些内容荣成城市规划建设局网站

有关外贸的网站有哪些内容,荣成城市规划建设局网站,物流网络结构模式有哪些,网站开发英语词汇“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕#xff1f; 尝试使用Okta API进行托管身份验证#xff0c;授权和多因素身份验证。 React的设计使创建交互式UI变得轻松自如。 它的状态管理非常有效#xff0c;并且仅在… “我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕 尝试使用Okta API进行托管身份验证授权和多因素身份验证。 React的设计使创建交互式UI变得轻松自如。 它的状态管理非常有效并且仅在数据更改时才更新组件。 组件逻辑是用JavaScript编写的这意味着您可以将状态保持在DOM之外并创建封装的组件。 开发人员喜欢CRUD创建读取更新和删除应用程序因为它们显示了创建应用程序时需要的许多基本功能。 一旦在应用程序中完成了CRUD的基础知识大多数客户端-服务器管道就完成了您可以继续实施必要的业务逻辑。 今天我将向您展示如何在React中使用Spring Boot创建一个基本的CRUD应用。 您可能还记得我去年为Angular撰写的一篇类似文章 使用Angular 5.0和Spring Boot 2.0构建Ba​​sic CRUD应用程序 。 该教程使用OAuth 2.0的隐式流程和我们的Okta Angular SDK 。 在本教程中我将使用OAuth 2.0授权代码流并将React应用打包在Spring Boot应用中进行生产。 同时我将向您展示如何保持React高效的工作流以进行本地开发。 您将需要安装Java 8 Node.js 8和Yarn才能完成本教程。 您可以使用npm代替Yarn但是您需要将Yarn语法转换为npm。 使用Spring Boot 2.0创建API应用 我经常在世界各地的会议和用户组中演讲。 我最喜欢发言的用户组是Java用户组JUG。 我从事Java开发人员已有近20年的时间而且我喜欢Java社区。 我的一个好朋友詹姆斯·沃德James Ward表示进行水罐巡游是他当时最喜欢的开发商倡导者活动之一。 我最近接受了他的建议并在海外会议上进行了JUG聚会在美国的聚会。 我为什么要告诉你呢 因为我认为今天创建一个“ JUG Tours”应用很有趣它允许您创建/编辑/删除JUG以及查看即将发生的事件。 首先导航至start.spring.io并进行以下选择 组 com.okta.developer 神器 jugtours 依赖项 JPA H2 Web Lombok 单击生成项目 下载后展开jugtours.zip 然后在您喜欢的IDE中打开该项目。 提示如果您使用的是IntelliJ IDEA或Spring Tool Suite则在创建新项目时也可以使用Spring Initializr。 添加一个JPA域模型 您需要做的第一件事是创建一个保存数据的域模型。 在高层次上有一个Group表示酒壶一个Event有一个多到一的关系Group 以及User具有与一个一对多的关系Group 。 创建一个src/main/java/com/okta/developer/jugtours/model目录和其中的Group.java类。 package com.okta.developer.jugtours.model;import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.RequiredArgsConstructor;import javax.persistence.*; import java.util.Set;Data NoArgsConstructor RequiredArgsConstructor Entity Table(name user_group) public class Group {IdGeneratedValueprivate Long id;NonNullprivate String name;private String address;private String city;private String stateOrProvince;private String country;private String postalCode;ManyToOne(cascadeCascadeType.PERSIST)private User user;OneToMany(fetch FetchType.EAGER, cascadeCascadeType.ALL)private SetEvent events; } 在同一包中创建一个Event.java类。 package com.okta.developer.jugtours.model;import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor;import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToMany; import java.time.Instant; import java.util.Set;Data NoArgsConstructor AllArgsConstructor Builder Entity public class Event {IdGeneratedValueprivate Long id;private Instant date;private String title;private String description;ManyToManyprivate SetUser attendees; } 还有一个User.java类。 package com.okta.developer.jugtours.model;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import javax.persistence.Entity; import javax.persistence.Id;Data NoArgsConstructor AllArgsConstructor Entity public class User {Idprivate String id;private String name;private String email; } 创建一个GroupRepository.java来管理组实体。 package com.okta.developer.jugtours.model;import org.springframework.data.jpa.repository.JpaRepository;import java.util.List;public interface GroupRepository extends JpaRepositoryGroup, Long {Group findByName(String name); } 要加载一些默认数据请在com.okta.developer.jugtours包中创建一个Initializer.java类。 package com.okta.developer.jugtours;import com.okta.developer.jugtours.model.Event; import com.okta.developer.jugtours.model.Group; import com.okta.developer.jugtours.model.GroupRepository; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component;import java.time.Instant; import java.util.Collections; import java.util.stream.Stream;Component class Initializer implements CommandLineRunner {private final GroupRepository repository;public Initializer(GroupRepository repository) {this.repository repository;}Overridepublic void run(String... strings) {Stream.of(Denver JUG, Utah JUG, Seattle JUG,Richmond JUG).forEach(name -repository.save(new Group(name)));Group djug repository.findByName(Denver JUG);Event e Event.builder().title(Full Stack Reactive).description(Reactive with Spring Boot React).date(Instant.parse(2018-12-12T18:00:00.000Z)).build();djug.setEvents(Collections.singleton(e));repository.save(djug);repository.findAll().forEach(System.out::println);} } 提示如果您的IDE Event.builder()问题则意味着您需要打开注释处理和/或安装Lombok插件。 我必须在IntelliJ IDEA中卸载/重新安装Lombok插件才能正常工作。 如果在添加此代码后启动应用程序使用./mvnw spring-boot:run 您将看到控制台中显示的组和事件列表。 Group(id1, nameDenver JUG, addressnull, citynull, stateOrProvincenull, countrynull, postalCodenull, usernull, events[Event(id5, date2018-12-12T18:00:00Z, titleFull Stack Reactive, descriptionReactive with Spring Boot React, attendees[])]) Group(id2, nameUtah JUG, addressnull, citynull, stateOrProvincenull, countrynull, postalCodenull, usernull, events[]) Group(id3, nameSeattle JUG, addressnull, citynull, stateOrProvincenull, countrynull, postalCodenull, usernull, events[]) Group(id4, nameRichmond JUG, addressnull, citynull, stateOrProvincenull, countrynull, postalCodenull, usernull, events[]) 添加一个GroupController.java类在src/main/java/.../jugtours/web/GroupController.java src/main/java/.../jugtours/web/GroupController.java可用于CRUD组。 package com.okta.developer.jugtours.web;import com.okta.developer.jugtours.model.Group; import com.okta.developer.jugtours.model.GroupRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*;import javax.validation.Valid; import java.net.URI; import java.net.URISyntaxException; import java.util.Collection; import java.util.Optional;RestController RequestMapping(/api) class GroupController {private final Logger log LoggerFactory.getLogger(GroupController.class);private GroupRepository groupRepository;public GroupController(GroupRepository groupRepository) {this.groupRepository groupRepository;}GetMapping(/groups)CollectionGroup groups() {return groupRepository.findAll();}GetMapping(/group/{id})ResponseEntity? getGroup(PathVariable Long id) {OptionalGroup group groupRepository.findById(id);return group.map(response - ResponseEntity.ok().body(response)).orElse(new ResponseEntity(HttpStatus.NOT_FOUND));}PostMapping(/group)ResponseEntityGroup createGroup(Valid RequestBody Group group) throws URISyntaxException {log.info(Request to create group: {}, group);Group result groupRepository.save(group);return ResponseEntity.created(new URI(/api/group/ result.getId())).body(result);}PutMapping(/group/{id})ResponseEntityGroup updateGroup(PathVariable Long id, Valid RequestBody Group group) {group.setId(id);log.info(Request to update group: {}, group);Group result groupRepository.save(group);return ResponseEntity.ok().body(result);}DeleteMapping(/group/{id})public ResponseEntity? deleteGroup(PathVariable Long id) {log.info(Request to delete group: {}, id);groupRepository.deleteById(id);return ResponseEntity.ok().build();} } 如果重新启动服务器应用程序并使用浏览器或命令行客户端访问http://localhost:8080/api/groups 则应看到组列表。 您可以使用以下HTTPie命令创建读取更新和删除组。 http POST :8080/api/group nameDublin JUG cityDublin countryIreland http :8080/api/group/6 http PUT :8080/api/group/6 nameDublin JUG cityDublin countryIreland addressDowntown http DELETE :8080/api/group/6使用Create React App创建一个React UI Create React App是一个命令行实用程序可为您生成React项目。 这是一个方便的工具因为它还提供了一些命令这些命令将生成和优化您的项目以进行生产。 它使用webpack在后台进行构建。 如果您想了解更多关于webpack的信息我建议使用webpack.academy 。 使用Yarn在jugtours目录中创建一个新项目。 yarn create react-app app 应用程序创建过程完成后导航至app目录并安装Bootstrap 对React的cookie支持React Router和Reactstrap 。 cd app yarn add bootstrap4.1.2 react-cookie2.2.0 react-router-dom4.3.1 reactstrap6.3.0 您将使用BootstrapCSS和Reactstrap的组件来使UI看起来更好尤其是在手机上。 如果您想了解有关Reactstrap的更多信息请参见https://reactstrap.github.io 。 它具有有关其各种组件以及如何使用它们的大量文档。 将BootstrapCSS文件添加为app/src/index.js的导入文件。 import bootstrap/dist/css/bootstrap.min.css;调用您的Spring Boot API并显示结果 修改app/src/App.js以使用以下代码调用/api/groups并在UI中显示列表。 import React, { Component } from react; import logo from ./logo.svg; import ./App.css;class App extends Component {state {isLoading: true,groups: []};async componentDidMount() {const response await fetch(/api/groups);const body await response.json();this.setState({ groups: body, isLoading: false });}render() {const {groups, isLoading} this.state;if (isLoading) {return pLoading.../p;}return (div classNameAppheader classNameApp-headerimg src{logo} classNameApp-logo altlogo /h1 classNameApp-titleWelcome to React/h1/headerdiv classNameApp-introh2JUG List/h2{groups.map(group div key{group.id}{group.name}/div)}/div/div);} }export default App; 要将代理从/api代理到http://localhost:8080/api 请将代理设置添加到app/package.json 。 scripts: {...}, proxy: http://localhost:8080 要了解有关此功能的更多信息请在app/README.md搜索“ proxy”。 Create React App随该文件附带了各种文档这有多酷 确保Spring Boot正在运行然后在您的app目录中运行yarn start 。 您应该看到默认组的列表。 构建一个React GroupList组件 React完全是关于组件的您不想在主App呈现所有内容因此请创建app/src/GroupList.js并使用以下JavaScript进行填充。 import React, { Component } from react; import { Button, ButtonGroup, Container, Table } from reactstrap; import AppNavbar from ./AppNavbar; import { Link } from react-router-dom;class GroupList extends Component {constructor(props) {super(props);this.state {groups: [], isLoading: true};this.remove this.remove.bind(this);}componentDidMount() {this.setState({isLoading: true});fetch(api/groups).then(response response.json()).then(data this.setState({groups: data, isLoading: false}));}async remove(id) {await fetch(/api/group/${id}, {method: DELETE,headers: {Accept: application/json,Content-Type: application/json}}).then(() {let updatedGroups [...this.state.groups].filter(i i.id ! id);this.setState({groups: updatedGroups});});}render() {const {groups, isLoading} this.state;if (isLoading) {return pLoading.../p;}const groupList groups.map(group {const address ${group.address || } ${group.city || } ${group.stateOrProvince || };return tr key{group.id}td style{{whiteSpace: nowrap}}{group.name}/tdtd{address}/tdtd{group.events.map(event {return div key{event.id}{new Intl.DateTimeFormat(en-US, {year: numeric,month: long,day: 2-digit}).format(new Date(event.date))}: {event.title}/div})}/tdtdButtonGroupButton sizesm colorprimary tag{Link} to{/groups/ group.id}Edit/ButtonButton sizesm colordanger onClick{() this.remove(group.id)}Delete/Button/ButtonGroup/td/tr});return (divAppNavbar/Container fluiddiv classNamefloat-rightButton colorsuccess tag{Link} to/groups/newAdd Group/Button/divh3My JUG Tour/h3Table classNamemt-4theadtrth width20%Name/thth width20%Location/ththEvents/thth width10%Actions/th/tr/theadtbody{groupList}/tbody/Table/Container/div);} }export default GroupList; 在同一目录中创建AppNavbar.js 以在组件之间建立通用的UI功能。 import React, { Component } from react; import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from reactstrap; import { Link } from react-router-dom;export default class AppNavbar extends Component {constructor(props) {super(props);this.state {isOpen: false};this.toggle this.toggle.bind(this);}toggle() {this.setState({isOpen: !this.state.isOpen});}render() {return Navbar colordark dark expandmdNavbarBrand tag{Link} to/Home/NavbarBrandNavbarToggler onClick{this.toggle}/Collapse isOpen{this.state.isOpen} navbarNav classNameml-auto navbarNavItemNavLinkhrefhttps://twitter.com/oktadevoktadev/NavLink/NavItemNavItemNavLink hrefhttps://github.com/oktadeveloper/okta-spring-boot-react-crud-exampleGitHub/NavLink/NavItem/Nav/Collapse/Navbar;} } 创建app/src/Home.js作为应用程序的登录页面。 import React, { Component } from react; import ./App.css; import AppNavbar from ./AppNavbar; import { Link } from react-router-dom; import { Button, Container } from reactstrap;class Home extends Component {render() {return (divAppNavbar/Container fluidButton colorlinkLink to/groupsManage JUG Tour/Link/Button/Container/div);} }export default Home; 另外更改app/src/App.js以使用React Router在组件之间导航。 import React, { Component } from react; import ./App.css; import Home from ./Home; import { BrowserRouter as Router, Route, Switch } from react-router-dom; import GroupList from ./GroupList;class App extends Component {render() {return (RouterSwitchRoute path/ exact{true} component{Home}/Route path/groups exact{true} component{GroupList}//Switch/Router)} }export default App; 为了使您的UI更加宽敞请在app/src/App.css容器类中添加一个上边距。 .container, .container-fluid {margin-top: 20px } 当您进行更改时您的React应用程序应该会自我更新并且您应该在http://localhost:3000看到如下屏幕。 点击Manage JUG Tour 您将看到默认组的列表。 可以在React应用程序中查看Spring Boot API的数据真是太好了但是如果您不能编辑它就不好玩了 添加一个React GroupEdit组件 创建app/src/GroupEdit.js并使用其componentDidMount()从URL中获取具有ID的组资源。 import React, { Component } from react; import { Link, withRouter } from react-router-dom; import { Button, Container, Form, FormGroup, Input, Label } from reactstrap; import AppNavbar from ./AppNavbar;class GroupEdit extends Component {emptyItem {name: ,address: ,city: ,stateOrProvince: ,country: ,postalCode: };constructor(props) {super(props);this.state {item: this.emptyItem};this.handleChange this.handleChange.bind(this);this.handleSubmit this.handleSubmit.bind(this);}async componentDidMount() {if (this.props.match.params.id ! new) {const group await (await fetch(/api/group/${this.props.match.params.id})).json();this.setState({item: group});}}handleChange(event) {const target event.target;const value target.value;const name target.name;let item {...this.state.item};item[name] value;this.setState({item});}async handleSubmit(event) {event.preventDefault();const {item} this.state;await fetch(/api/group, {method: (item.id) ? PUT : POST,headers: {Accept: application/json,Content-Type: application/json},body: JSON.stringify(item),});this.props.history.push(/groups);}render() {const {item} this.state;const title h2{item.id ? Edit Group : Add Group}/h2;return divAppNavbar/Container{title}Form onSubmit{this.handleSubmit}FormGroupLabel fornameName/LabelInput typetext namename idname value{item.name || }onChange{this.handleChange} autoCompletename//FormGroupFormGroupLabel foraddressAddress/LabelInput typetext nameaddress idaddress value{item.address || }onChange{this.handleChange} autoCompleteaddress-level1//FormGroupFormGroupLabel forcityCity/LabelInput typetext namecity idcity value{item.city || }onChange{this.handleChange} autoCompleteaddress-level1//FormGroupdiv classNamerowFormGroup classNamecol-md-4 mb-3Label forstateOrProvinceState/Province/LabelInput typetext namestateOrProvince idstateOrProvince value{item.stateOrProvince || }onChange{this.handleChange} autoCompleteaddress-level1//FormGroupFormGroup classNamecol-md-5 mb-3Label forcountryCountry/LabelInput typetext namecountry idcountry value{item.country || }onChange{this.handleChange} autoCompleteaddress-level1//FormGroupFormGroup classNamecol-md-3 mb-3Label forcountryPostal Code/LabelInput typetext namepostalCode idpostalCode value{item.postalCode || }onChange{this.handleChange} autoCompleteaddress-level1//FormGroup/divFormGroupButton colorprimary typesubmitSave/Button{ }Button colorsecondary tag{Link} to/groupsCancel/Button/FormGroup/Form/Container/div} }export default withRouter(GroupEdit); 底部需要使用withRouter()高阶组件来显示this.props.history因此您可以在添加或保存GroupList后导航回this.props.history 。 修改app/src/App.js以导入GroupEdit并指定其路径。 import GroupEdit from ./GroupEdit;class App extends Component {render() {return (RouterSwitch...Route path/groups/:id component{GroupEdit}//Switch/Router)} } 现在您应该可以添加和编辑组了 使用Okta添加身份验证 构建CRUD应用程序非常酷但是构建安全的应用程序甚至更酷。 为此您需要添加身份验证以便用户必须先登录才能查看/修改组。 为简化起见您可以使用Okta的OIDC API。 在Okta我们的目标是使身份管理比您以往更加轻松安全和可扩展。 Okta是一项云服务允许开发人员创建编辑和安全地存储用户帐户和用户帐户数据并将它们与一个或多个应用程序连接。 我们的API使您能够 验证和授权用户 存储有关您的用户的数据 执行基于密码的社交登录 通过多因素身份验证保护您的应用程序 以及更多 查看我们的产品文档 你卖了吗 注册一个永久免费的开发者帐户 完成后再回来这样您就可以了解有关使用Spring Boot构建安全应用程序的更多信息 Spring Security OIDC Spring Security在其5.0版本中增加了OIDC支持 。 从那时起他们进行了许多改进并简化了所需的配置。 我认为探索最新和最有趣的东西很有趣所以我首先使用Spring的快照存储库更新pom.xml 将Spring Boot和Spring Security升级到夜间构建并添加必要的Spring Security依赖项来进行OIDC身份验证。 ?xml version1.0 encodingUTF-8? project...parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.1.0.BUILD-SNAPSHOT/versionrelativePath/ !-- lookup parent from repository --/parentproperties...spring-security.version5.1.0.BUILD-SNAPSHOT/spring-security.version/propertiesdependencies...dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId/dependencydependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-config/artifactId/dependencydependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-oauth2-client/artifactId/dependencydependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-oauth2-jose/artifactId/dependency/dependenciesbuild...pluginRepositoriespluginRepositoryidspring-snapshots/idnameSpring Snapshots/nameurlhttps://repo.spring.io/snapshot/urlsnapshotsenabledtrue/enabled/snapshots/pluginRepository/pluginRepositoriesrepositoriesrepositoryidspring-snapshots/idnameSpring Snapshot/nameurlhttp://repo.spring.io/snapshot/url/repository/repositories /project在Okta中创建OIDC应用 登录到您的1563开发者帐户或者注册 如果你没有一个帐户并导航到应用程序 添加应用程序 。 单击“ Web” 然后单击“ 下一步” 。 给应用程序起一个您会记住的名称并指定http://localhost:8080/login/oauth2/code/okta作为登录重定向URI。 点击完成 然后点击编辑以编辑常规设置。 添加http://localhost:3000和http://localhost:8080作为注销重定向URI然后点击保存 。 将默认授权服务器的URI客户端ID和客户端密钥复制并粘贴到src/main/resources/application.yml 。 创建此文件然后可以删除同一目录中的application.properties文件。 spring:security:oauth2:client:registration:okta:client-id: {clientId}client-secret: {clientSecret}scope: openid email profileprovider:okta:issuer-uri: https://{yourOktaDomain}/oauth2/default为React和用户身份配置Spring Security 为了使Spring Security React友好请在src/main/java/.../jugtours/config创建一个SecurityConfiguration.java文件。 创建config目录并将该类放入其中。 package com.okta.developer.jugtours.config;import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest;import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map;Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter {private final Logger log LoggerFactory.getLogger(SecurityConfiguration.class);Overrideprotected void configure(HttpSecurity http) throws Exception {RequestCache requestCache refererRequestCache();SavedRequestAwareAuthenticationSuccessHandler handler new SavedRequestAwareAuthenticationSuccessHandler();handler.setRequestCache(requestCache);http.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint(/oauth2/authorization/okta)).and().oauth2Login().successHandler(handler).and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and().requestCache().requestCache(requestCache).and().authorizeRequests().antMatchers(/**/*.{js,html,css}).permitAll().antMatchers(/, /api/user).permitAll().anyRequest().authenticated();}Beanpublic RequestCache refererRequestCache() {return new RequestCache() {private String savedAttrName getClass().getName().concat(.SAVED);Overridepublic void saveRequest(HttpServletRequest request, HttpServletResponse response) {String referrer request.getHeader(referer);if (referrer ! null) {request.getSession().setAttribute(this.savedAttrName, referrerRequest(referrer));}}Overridepublic SavedRequest getRequest(HttpServletRequest request, HttpServletResponse response) {HttpSession session request.getSession(false);if (session ! null) {return (SavedRequest) session.getAttribute(this.savedAttrName);}return null;}Overridepublic HttpServletRequest getMatchingRequest(HttpServletRequest request, HttpServletResponse response) {return request;}Overridepublic void removeRequest(HttpServletRequest request, HttpServletResponse response) {HttpSession session request.getSession(false);if (session ! null) {log.debug(Removing SavedRequest from session if present);session.removeAttribute(this.savedAttrName);}}};}private SavedRequest referrerRequest(final String referrer) {return new SavedRequest() {Overridepublic String getRedirectUrl() {return referrer;}Overridepublic ListCookie getCookies() {return null;}Overridepublic String getMethod() {return null;}Overridepublic ListString getHeaderValues(String name) {return null;}Overridepublic CollectionString getHeaderNames() {return null;}Overridepublic ListLocale getLocales() {return null;}Overridepublic String[] getParameterValues(String name) {return new String[0];}Overridepublic MapString, String[] getParameterMap() {return null;}};} } 这堂课正在进行很多所以让我解释一些事情。 在年初configure()方法你建立一个新类型缓存网址标头拼错请求缓存的referer在现实生活中所以Spring Security可以验证后回重定向到它。 当您在http://localhost:3000上开发React并希望在登录后重定向到那里时基于引用者的请求缓存会派上用场。 Override protected void configure(HttpSecurity http) throws Exception {RequestCache requestCache refererRequestCache();SavedRequestAwareAuthenticationSuccessHandler handler new SavedRequestAwareAuthenticationSuccessHandler();handler.setRequestCache(requestCache);http.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint(/oauth2/authorization/okta)).and().oauth2Login().successHandler(handler).and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and().requestCache().requestCache(requestCache).and().authorizeRequests().antMatchers(/**/*.{js,html,css}).permitAll().antMatchers(/, /api/user).permitAll().anyRequest().authenticated(); } authenticationEntryPoint()行使Spring Security自动重定向到Okta。 在Spring Security 5.1.0.RELEASE中当您仅配置一个OIDC提供程序时将不需要此行。 它会自动重定向。 使用CookieCsrfTokenRepository.withHttpOnlyFalse()配置CSRF跨站点请求伪造保护意味着XSRF-TOKEN cookie将不会被标记为仅HTTP因此React可以读取它并在尝试操作数据时将其发送回去。 antMatchers行定义了匿名用户可以使用哪些URL。 您将很快进行配置以便由Spring Boot应用程序服务您的React应用程序因此允许使用Web文件和“ /”的原因。 您可能会注意到也有一个公开的/api/user路径。 创建src/main/java/.../jugtours/web/UserController.java并使用以下代码填充它。 React将使用此API来1找出用户是否已通过身份验证以及2执行全局注销。 package com.okta.developer.jugtours.web;import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.core.oidc.OidcIdToken; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map;RestController public class UserController {Value(${spring.security.oauth2.client.provider.okta.issuer-uri})String issuerUri;GetMapping(/api/user)public ResponseEntity? getUser(AuthenticationPrincipal OAuth2User user) {if (user null) {return new ResponseEntity(, HttpStatus.OK);} else {return ResponseEntity.ok().body(user.getAttributes());}}PostMapping(/api/logout)public ResponseEntity? logout(HttpServletRequest request,AuthenticationPrincipal(expression idToken) OidcIdToken idToken) {// send logout URL to client so they can initiate logout - doesnt work from the server side// Make it easier: https://github.com/spring-projects/spring-security/issues/5540String logoutUrl issuerUri /v1/logout;MapString, String logoutDetails new HashMap();logoutDetails.put(logoutUrl, logoutUrl);logoutDetails.put(idToken, idToken.getTokenValue());request.getSession(false).invalidate();return ResponseEntity.ok().body(logoutDetails);} } 您还需要创建组时这样就可以通过你的壶之旅筛选添加用户信息。 在与GroupRepository.java相同的目录中添加UserRepository.java 。 package com.okta.developer.jugtours.model;import org.springframework.data.jpa.repository.JpaRepository;public interface UserRepository extends JpaRepositoryUser, String { } 将新的findAllByUserId(String id)方法添加到GroupRepository.java 。 ListGroup findAllByUserId(String id); 然后将UserRepository注入GroupController.java并在添加新组时使用它来创建或获取现有用户。 在那里请修改groups()方法以按用户过滤。 package com.okta.developer.jugtours.web;import com.okta.developer.jugtours.model.Group; import com.okta.developer.jugtours.model.GroupRepository; import com.okta.developer.jugtours.model.User; import com.okta.developer.jugtours.model.UserRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.web.bind.annotation.*;import javax.validation.Valid; import java.net.URI; import java.net.URISyntaxException; import java.security.Principal; import java.util.Collection; import java.util.Map; import java.util.Optional;RestController RequestMapping(/api) class GroupController {private final Logger log LoggerFactory.getLogger(GroupController.class);private GroupRepository groupRepository;private UserRepository userRepository;public GroupController(GroupRepository groupRepository, UserRepository userRepository) {this.groupRepository groupRepository;this.userRepository userRepository;}GetMapping(/groups)CollectionGroup groups(Principal principal) {return groupRepository.findAllByUserId(principal.getName());}GetMapping(/group/{id})ResponseEntity? getGroup(PathVariable Long id) {OptionalGroup group groupRepository.findById(id);return group.map(response - ResponseEntity.ok().body(response)).orElse(new ResponseEntity(HttpStatus.NOT_FOUND));}PostMapping(/group)ResponseEntityGroup createGroup(Valid RequestBody Group group,AuthenticationPrincipal OAuth2User principal) throws URISyntaxException {log.info(Request to create group: {}, group);MapString, Object details principal.getAttributes();String userId details.get(sub).toString();// check to see if user already existsOptionalUser user userRepository.findById(userId);group.setUser(user.orElse(new User(userId,details.get(name).toString(), details.get(email).toString())));Group result groupRepository.save(group);return ResponseEntity.created(new URI(/api/group/ result.getId())).body(result);}PutMapping(/group)ResponseEntityGroup updateGroup(Valid RequestBody Group group) {log.info(Request to update group: {}, group);Group result groupRepository.save(group);return ResponseEntity.ok().body(result);}DeleteMapping(/group/{id})public ResponseEntity? deleteGroup(PathVariable Long id) {log.info(Request to delete group: {}, id);groupRepository.deleteById(id);return ResponseEntity.ok().build();} } 为了放大更改它们在groups()和createGroup()方法中。 Spring JPA会为您创建findAllByUserId()方法/查询并且userRepository.findById()使用Java 8的Optional 这是一个很好的选择 。 GetMapping(/groups) CollectionGroup groups(Principal principal) {return groupRepository.findAllByUserId(principal.getName()); }PostMapping(/group) ResponseEntityGroup createGroup(Valid RequestBody Group group,AuthenticationPrincipal OAuth2User principal) throws URISyntaxException {log.info(Request to create group: {}, group);MapString, Object details principal.getAttributes();String userId details.get(sub).toString();// check to see if user already existsOptionalUser user userRepository.findById(userId);group.setUser(user.orElse(new User(userId,details.get(name).toString(), details.get(email).toString())));Group result groupRepository.save(group);return ResponseEntity.created(new URI(/api/group/ result.getId())).body(result); }修改React Handle CSRF并识别身份 您需要对React组件进行一些更改以使它们能够识别身份。 您要做的第一件事是修改App.js以将所有内容包装在CookieProvider 。 该组件允许您读取CSRF cookie并将其作为标题发送回。 import { CookiesProvider } from react-cookie;class App extends Component {render() {return (CookiesProviderRouter.../CookiesProvider)} } 修改app/src/Home.js以调用/api/user来查看用户是否已登录。如果没有Login 请显示“ Login按钮。 import React, { Component } from react; import ./App.css; import AppNavbar from ./AppNavbar; import { Link } from react-router-dom; import { Button, Container } from reactstrap; import { withCookies } from react-cookie;class Home extends Component {state {isLoading: true,isAuthenticated: false,user: undefined};constructor(props) {super(props);const {cookies} props;this.state.csrfToken cookies.get(XSRF-TOKEN);this.login this.login.bind(this);this.logout this.logout.bind(this);}async componentDidMount() {const response await fetch(/api/user, {credentials: include});const body await response.text();if (body ) {this.setState(({isAuthenticated: false}))} else {this.setState({isAuthenticated: true, user: JSON.parse(body)})}}login() {let port (window.location.port ? : window.location.port : );if (port :3000) {port :8080;}window.location.href // window.location.hostname port /private;}logout() {console.log(logging out...);fetch(/api/logout, {method: POST, credentials: include,headers: {X-XSRF-TOKEN: this.state.csrfToken}}).then(res res.json()).then(response {window.location.href response.logoutUrl ?id_token_hint response.idToken post_logout_redirect_uri window.location.origin;});}render() {const message this.state.user ?h2Welcome, {this.state.user.name}!/h2 :pPlease log in to manage your JUG Tour./p;const button this.state.isAuthenticated ?divButton colorlinkLink to/groupsManage JUG Tour/Link/Buttonbr/Button colorlink onClick{this.logout}Logout/Button/div :Button colorprimary onClick{this.login}Login/Button;return (divAppNavbar/Container fluid{message}{button}/Container/div);} }export default withCookies(Home); 您应该在此组件中注意一些事项 withCookies()将Home组件包装在底部以使其可以访问cookie。 然后您可以在构造const {cookies} props中使用const {cookies} props 并使用cookies.get(XSRF-TOKEN)获取cookie。 使用fetch() 需要包括{credentials: include}来传输cookie。 如果不包含此选项则将获得“ 403禁止访问”。 Spring Security的CSRF cookie的名称与您需要发回的标头的名称不同。 cookie名称是XSRF-TOKEN 而标题名称是X-XSRF-TOKEN 。 更新app/src/GroupList.js以进行类似更改。 好消息是您不需要对render()方法进行任何更改。 import { Link, withRouter } from react-router-dom; import { instanceOf } from prop-types; import { withCookies, Cookies } from react-cookie;class GroupList extends Component {static propTypes {cookies: instanceOf(Cookies).isRequired};constructor(props) {super(props);const {cookies} props;this.state {groups: [], csrfToken: cookies.get(XSRF-TOKEN), isLoading: true};this.remove this.remove.bind(this);}componentDidMount() {this.setState({isLoading: true});fetch(api/groups, {credentials: include}).then(response response.json()).then(data this.setState({groups: data, isLoading: false})).catch(() this.props.history.push(/))}async remove(id) {await fetch(/api/group/${id}, {method: DELETE,headers: {X-XSRF-TOKEN: this.state.csrfToken,Accept: application/json,Content-Type: application/json},credentials: include}).then(() {let updatedGroups [...this.state.groups].filter(i i.id ! id);this.setState({groups: updatedGroups});});}render() {...} }export default withCookies(withRouter(GroupList)); 也更新GroupEdit.js 。 import { instanceOf } from prop-types; import { Cookies, withCookies } from react-cookie;class GroupEdit extends Component {static propTypes {cookies: instanceOf(Cookies).isRequired};emptyItem {name: ,address: ,city: ,stateOrProvince: ,country: ,postalCode: };constructor(props) {super(props);const {cookies} props;this.state {item: this.emptyItem,csrfToken: cookies.get(XSRF-TOKEN)};this.handleChange this.handleChange.bind(this);this.handleSubmit this.handleSubmit.bind(this);}async componentDidMount() {if (this.props.match.params.id ! new) {try {const group await (await fetch(/api/group/${this.props.match.params.id}, {credentials: include})).json();this.setState({item: group});} catch (error) {this.props.history.push(/);}}}handleChange(event) {const target event.target;const value target.value;const name target.name;let item {...this.state.item};item[name] value;this.setState({item});}async handleSubmit(event) {event.preventDefault();const {item, csrfToken} this.state;await fetch(/api/group, {method: (item.id) ? PUT : POST,headers: {X-XSRF-TOKEN: csrfToken,Accept: application/json,Content-Type: application/json},body: JSON.stringify(item),credentials: include});this.props.history.push(/groups);}render() {...} }export default withCookies(withRouter(GroupEdit)); 完成所有这些更改之后您应该能够重新启动Spring Boot和React并见证计划自己的JUG Tour的荣耀 配置Maven以使用Spring Boot构建和打包React 要使用Maven构建和打包React应用可以使用frontend-maven-plugin和Maven的配置文件将其激活。 将版本的属性和profiles部分添加到pom.xml 。 properties...frontend-maven-plugin.version1.6/frontend-maven-plugin.versionnode.versionv10.6.0/node.versionyarn.versionv1.8.0/yarn.version /propertiesprofilesprofileiddev/idactivationactiveByDefaulttrue/activeByDefault/activationpropertiesspring.profiles.activedev/spring.profiles.active/properties/profileprofileidprod/idbuildpluginspluginartifactIdmaven-resources-plugin/artifactIdexecutionsexecutionidcopy-resources/idphaseprocess-classes/phasegoalsgoalcopy-resources/goal/goalsconfigurationoutputDirectory${basedir}/target/classes/static/outputDirectoryresourcesresourcedirectoryapp/build/directory/resource/resources/configuration/execution/executions/pluginplugingroupIdcom.github.eirslett/groupIdartifactIdfrontend-maven-plugin/artifactIdversion${frontend-maven-plugin.version}/versionconfigurationworkingDirectoryapp/workingDirectory/configurationexecutionsexecutionidinstall node/idgoalsgoalinstall-node-and-yarn/goal/goalsconfigurationnodeVersion${node.version}/nodeVersionyarnVersion${yarn.version}/yarnVersion/configuration/executionexecutionidyarn install/idgoalsgoalyarn/goal/goalsphasegenerate-resources/phase/executionexecutionidyarn test/idgoalsgoalyarn/goal/goalsphasetest/phaseconfigurationargumentstest/arguments/configuration/executionexecutionidyarn build/idgoalsgoalyarn/goal/goalsphasecompile/phaseconfigurationargumentsbuild/arguments/configuration/execution/executions/plugin/plugins/buildpropertiesspring.profiles.activeprod/spring.profiles.active/properties/profile /profiles 在使用时将活动配置文件设置添加到src/main/resources/application.yml spring:profiles:active: spring.profiles.activesecurity: 添加./mvnw spring-boot:run -Pprod之后您应该可以运行./mvnw spring-boot:run -Pprod并且您的应用程序可以看到您的应用程序在http://localhost:8080 。 注意如果您无法登录则可以尝试在隐身窗口中打开您的应用程序。 Spring Security的OAuth 2.0与OIDC支持 在撰写这篇文章时我与Rob Winch Spring Security Lead合作以确保我有效地使用了Spring Security。 我开始使用Spring Security的OAuth 2.0支持及其EnableOAuth2Sso批注。 Rob鼓励我改用Spring Security的OIDC支持这对使一切正常发挥了作用。 随着Spring Boot 2.1和Spring Security 5.1的里程碑和发行版的发布我将更新此帖子以删除不再需要的代码。 了解有关Spring Boot和React的更多信息 我希望您喜欢本教程了解如何使用ReactSpring Boot和Spring Security进行CRUD。 您可以看到Spring Security的OIDC支持非常强大并且不需要大量配置。 添加CSRF保护并将Spring Boot React应用打包为单个工件也很酷 您可以在GitHub上的https://github.com/oktadeveloper/okta-spring-boot-react-crud-example上找到本教程中创建的示例。 我们还编写了其他一些很棒的Spring Boot和React教程如果您有兴趣的话可以查看它们。 使用Spring Boot和React进行Bootiful开发 构建一个React Native应用程序并使用OAuth 2.0进行身份验证 使用Jenkins X和Kubernetes将CI / CD添加到您的Spring Boot应用程序 15分钟内通过用户身份验证构建React应用程序 如有任何疑问请随时在下面发表评论或在我们的Okta开发者论坛上向我们提问。 如果您想查看更多类似的教程请在Twitter上关注我们 “我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕 尝试使用Okta API进行托管身份验证授权和多因素身份验证。 使用React和Spring Boot构建简单的CRUD应用程序最初于2018年7月19日发布在Okta开发者博客上。 翻译自: https://www.javacodegeeks.com/2018/07/react-spring-boot-build-crud-app.html
http://www.pierceye.com/news/490975/

相关文章:

  • 网站数据分析视频深圳市昊客网络科技有限公司
  • 外贸网站做开关行业的哪个好网站互动优化
  • 西班牙语网站设计哪家好开发一个跑腿app需要多少钱
  • 怎么才能提高网站点击量 免费网站原型图软件
  • wordpress私人建站主题网络公司手机网站
  • 做网站设计比较好的公司wordpress wp_trim_words
  • 湖南对外建设集团网站wordpress中数据库配置文件
  • 设计类网站模板物流企业网站建设策划书
  • dw建设手机网站永久免费网站推荐
  • 微信官方网站怎么进入自己做网站推广试玩
  • 郑州网站建设老牌公司贵州省城乡建设厅网站材料价
  • 网站建设费是什么上海建设网站公司
  • 怎么查出这个网站是谁做的谷歌首页
  • 桂林网站建设国内crm系统哪家好
  • 网站建设数据库配置查看商标是否被注册官网
  • 关于网站制作做网站用com还是cn好
  • 手机网站支付网站建设 sheji021
  • 兴义网站制作网上开的公司网站打不开
  • 三只松鼠的网站建设理念桐庐营销型网站建设
  • 建设银行网站未响应大理如何做百度的网站
  • 广州建立公司网站多少钱页面跳转不了怎么回事
  • 爱做的小说网站吗百度权重高的发帖网站
  • 做网站的空间费用要多少产品怎么做推广和宣传
  • 商城网站制作明细老牌深圳公司大雨中解散
  • wordpress缩略图设置百度站长工具seo
  • 建站还有前途么食品包装设计规范及包装标准
  • 专门做漫画的网站企业网站改版seo
  • 最新网站建设合同做网站在哪里添加关键词
  • 集团网站开发多少钱做网站不难吧
  • 全总基层组织建设网站百度录入网站