投稿時間:2023-02-05 19:15:24 RSSフィード2023-02-05 19:00 分まとめ(17件)

カテゴリー等 サイト名等 記事タイトル・トレンドワード等 リンクURL 頻出ワード・要約等/検索ボリューム 登録日
AWS lambdaタグが付けられた新着投稿 - Qiita 想定外のメール大量送信によるSNSサブスクリプションの非アクティブ化に対処する https://qiita.com/Satelliter/items/ba263707ad05e87fa6a7 urlamazons 2023-02-05 18:30:28
python Pythonタグが付けられた新着投稿 - Qiita python-VLCを使用したミュージックプレイヤー https://qiita.com/reiji990/items/e941dc90c50e0b9febd3 erwithpythonvlcpythonvlc 2023-02-05 18:25:31
python Pythonタグが付けられた新着投稿 - Qiita [Python]Dataframeで簡単に行の変化率を計算する https://qiita.com/yuandesu/items/acc89265e87e1d22ed9c dimportpandasaspddatadate 2023-02-05 18:10:27
js JavaScriptタグが付けられた新着投稿 - Qiita TypeScriptのinterfaceについて https://qiita.com/wemark/items/f374c4311a428acb57d0 interface 2023-02-05 18:16:54
js JavaScriptタグが付けられた新着投稿 - Qiita React Three Fiberで作成したComponentをStorybookで管理する - Effect編 https://qiita.com/t_shi/items/87ac57051fbce712b2ae component 2023-02-05 18:12:20
js JavaScriptタグが付けられた新着投稿 - Qiita Next.jsでのLinkコンポーネントの記述の仕方で変更点をおさえる!! https://qiita.com/naofunky/items/0824e221ec31054bdd57 nextjs 2023-02-05 18:06:45
AWS AWSタグが付けられた新着投稿 - Qiita 想定外のメール大量送信によるSNSサブスクリプションの非アクティブ化に対処する https://qiita.com/Satelliter/items/ba263707ad05e87fa6a7 urlamazons 2023-02-05 18:30:28
AWS AWSタグが付けられた新着投稿 - Qiita 簡易IPアドレス自動ブロック機能の実装 https://qiita.com/watta10/items/10f83fd4df0d32bba2e0 awslambda 2023-02-05 18:07:43
golang Goタグが付けられた新着投稿 - Qiita シーク法のgoでの実装 https://qiita.com/Hiroaki-K4/items/7b577c3bb63016f1aa2e offset 2023-02-05 18:04:41
Git Gitタグが付けられた新着投稿 - Qiita git, githubのメモ https://qiita.com/kajiyai/items/9d3da1bc13ee244d536b commitaddpush 2023-02-05 18:12:35
海外TECH DEV Community How to build a collaborative SaaS product using Next.js and ZenStack's access control policy https://dev.to/zenstack/how-to-build-a-collaborative-saas-product-using-nextjs-and-zenstacks-access-control-policy-1nc1 How to build a collaborative SaaS product using Next js and ZenStack x s access control policy PrefaceInitially I was planning to write it in two series step by step How to build a non collaborative ToDo productHow to add the collaborative partWhen one of my friends who happened to be building a SaaS product knew about it she told me that she didn t think anyone would be interested in the first of the series as no one would actually build a ToDo product Instead she is very interested in how to build the collaborative part of the SaaS product properly It reminds me of a famous discussion about the MVP which is usually illustrated as However there is a problem with it It looks just like the problem of mine my friend told me about So I decided first to show you how to build a collaborative SaaS team space firstly in this article BackgroundTechnically one of the most important things to consider for SaaS products is tenant isolation To put it in a single word users from tenant A should not be able to access data from tenant B and vice versa The idea behind tenant isolation is access control A classic challenge when laying foundations for BB SaaS is striking a balance between app security and dev productivity There is a typical way of dealing with it using physical isolation which means each tenant will have its own database schema Definitely it provides the best security but it will also make your architecture more complicated and cost you more effort to deal with the database especially considering the cross database resources Another alternative way is to do virtual isolation which means flagging all tenant specific records in your DB with a tenantId key Each incoming request that hits the DB must then be scoped against the current tenantId To make it DRY Don t repeat yourself usually you would adopt some middleware to handle it like below const databaseMiddleware req res next gt const incomingMessage req as IncomingMessage const serverResponse res as ServerResponse Get the tenant ID from the request object const tenantId incomingMessage tenantId Add the tenant ID filter to all database queries addTenantIdFilter tenantId next const addTenantIdFilter tenantId string gt Implement the logic to add the tenant ID filter to all database queries It probably works well at the beginning But as your product grows with more kinds of resources together with a specific access control policy it might become error prone because the access control logic is dispersed in the middleware and specific API logic One of the most important things ZenStack is trying to solve is allowing you to define access policies directly inside your data model so it s easier to keep the policies in sync when your data models evolve So Let s see how we could achieve that using the declarative way provided by ZenStack PrerequisiteMake sure you have Node js or above installed Install the VSCode extension for editing data models You already have a basic idea about Prisma If not you can either check its website or read this article Building the appIf you don t want to follow the detailed steps you can also find the deployed version and complete code below Create a new projectCreate a Next js project with create t app with Prisma NextAuth and TailwindCSS npx create t app latest prisma nextAuth tailwind CI my saas appcd my saas appnpm run dev Initialize the project for ZenStackLet s run the zenstack CLI to prepare your project for using ZenStack npx zenstack latest initThe command installs a few NPM dependencies and copies the Prisma schema from prisma schema prismato schema zmodel The only models we still need are Account and User you can remove other models Define schema RelationsTenant is more from the technical world from the business world we usually call Space So let s create a model for it model Space id String id default uuid name String length slug String unique regex a zA Z In addition to the Prisma schema it has two attributes length and regex which is the standard validation attribute provided by ZenStack library Actually one enhancement to Prisma of ZenStack is to be able to define your own custom attribute Then we need to model the relationship between Space and User It s a typical many to many relation So we need to add a relation model SpaceUser Model representing membership of a user in a space model SpaceUser id String id default uuid space Space relation fields spaceId references id onDelete Cascade spaceId String user User relation fields userId references id onDelete Cascade userId String role SpaceUserRole enum SpaceUserRole USER ADMIN Then we should also add this relation in both Space and Usermodel User spaces SpaceUser model Space members SpaceUser Access PolicyAccess policies are expressed with the  allowand  denymodel attributes The attributes take two parameters The first is the operation create read update delete You can use a comma separated string to pass multiple operations or use all to abbreviate all operations The second parameter is a boolean expression indicating if the rule should be activated allow opens up permissions while  deny turns them off You can use them multiple times and combine them in a model Whether an operation is permitted is determined as follows If any  deny rule evaluates to true it s denied If any  allow rule evaluates to true it s allowed Otherwise it s denied Userthe access rule for User should be defined as model User spaces SpaceUser can be created by anyone even not logged in allow create true can be read by users sharing any space allow read spaces space members user auth full access by oneself allow all auth this auth is a special function provided by ZenStack to return the current authenticated User instance which represents the user identity of the current data request after wrapping Prisma client which I will show you how to do it later The first and third rules should be straightforward So let s talk about the second rule which actually implements tenant isolation It uses the Any condition syntax in Collection Predicate Expression lt collection gt condition It means any element in collection matches condition And the condition expression has direct access to fields defined in the model of collection It might be a little hard to understand because there are actually two “users here One is the authenticated user currently initiating the data request the other one is the target user data the request is trying to access To make it easy to understand let s use Auth to refer to the current user and use Bob to refer to the data as below the outer condition spaces … means if the inner condition satisfies any space Bob belongs to then Bob could be read The inner condition space members user auth means if Auth belongs to the space So combining the logic together if Auth belongs to any of the Space of Bob then Bob could be read It s might be a little hard to follow the logic at the beginning but once you get familiar with it you will feel natural and intuitive to use it Spacemodel Space members SpaceUser require login deny all auth null everyone can create a space allow create true any user in the space can read the space allow read members user auth space admin can update and delete allow update delete members user auth amp amp role ADMIN SpaceUsermodel SpaceUser space Space relation fields spaceId references id onDelete Cascade require login deny all auth null space admin can create update delete allow create update delete space members user auth amp amp role ADMIN user can read entries for spaces which he s a member of allow read space members user auth I bet the rules for Space and SpaceUser already looks intuitive to you right Notice the first allow rule in SpaceUser restrict that only the space admin could manage the space member We will see how it takes effect later That s all we need to do to support tenant isolation You could use the Prisma style react hooks or the ZenStack wrapped Prisma client as usual the access control just works as you defined in the schema under the hood How ZenStack generates the safeguard for all the API calls based on your access policy You will see it soon Last changeFor simplicity we ll use username password based authentication in this project So let s add password field in User model model User password String password omit password marks the field to be based before saving omit indicates the field should be dropped when returning from a query Since we defined an Enum SpaceUserRole which is not supported by the SQLite we need to use a real database provider I will use PostgreSQL in this project So let s change it in the schema datasource db provider postgresql url env DATABASE URL If you don t have a Postgres database the simple way to get one is to get a docker instance or a free one from Supabase Now let s run the below command to flush the change to the Prisma schema and database npx zenstack generate amp amp npx prisma db pushAfter running successfully you can open this file node modules zenstack policy ts and see the function like this function User read context QueryContext any const user context user null return OR spaces some space is members some user zenstack guard false user is id equals user user id null user zenstack guard false id equals user user id null That s the safeguard I mentioned above which translates the access policy defined in the schema to the actual code Sign up Sign in NextAuthLet s update  src pages api auth nextauth tsto the content below to use credentials auth and JWT based session import PrismaAdapter from next auth prisma adapter import PrismaClient from prisma client import compare from bcryptjs import NextAuth NextAuthOptions from next auth import CredentialsProvider from next auth providers credentials import prisma from server db export const authOptions NextAuthOptions adapter PrismaAdapter prisma session strategy jwt providers CredentialsProvider credentials email type email password type password authorize authorize prisma callbacks async session session token return session user session user id token sub function authorize prisma PrismaClient return async credentials Record lt email password string gt undefined gt if credentials throw new Error Missing credentials if credentials email throw new Error email is required in credentials if credentials password throw new Error password is required in credentials const maybeUser await prisma user findFirst where email credentials email select id true email true password true if maybeUser maybeUser password return null const isValid await compare credentials password maybeUser password if isValid return null return id maybeUser id email maybeUser email export default NextAuth authOptions Then let s add the add NEXTAUTH SECRETenvironment variable in env file and set it to an arbitrary value like the below NEXTAUTH SECRET abc Mount CRUD service amp generate hooksZenStack has built in support for Next js and can provide database CRUD services automatically so you don t need to write it yourself First install the  zenstackhq nextand  zenstackhq reactpackages npm install zenstackhq next zenstackhq reactLet s create a new file src server enhanced db tsimport withPresets from zenstackhq runtime import type GetServerSidePropsContext from next import getServerAuthSession from auth import prisma from db export async function getEnhancedPrisma ctx req GetServerSidePropsContext req res GetServerSidePropsContext res const session await getServerAuthSession ctx create a wrapper of Prisma client that enforces access policy data validation and password omit behaviors return withPresets prisma user session user Then whenever you want to use Prisma client you can use getEnhancedPrisma instead whichautomatically validates access policies field validation rules etc during CRUD operations Now let s create our API endpoint in src pages api model path and fill in the content below import requestHandler from zenstackhq next import getEnhancedPrisma from server enhanced db export default requestHandler getPrisma req res gt getEnhancedPrisma req res The  api model route is now ready to access database queries and mutation requests However manually calling the service will be tedious Fortunately ZenStack can automatically generate React hooks for you Let s enable it by adding the following snippet at the top level to schema zmodel plugin reactHooks provider zenstackhq react output src lib hook Now run npx zenstack generate again you ll find the hooks generated under  src lib hooks folder npx zenstack generateNow we re ready to implement the signup signin flow Sign upFirst let s create a signup page under src pages singup tsxTo make the post not too long I will only show the logic code snippets For the complete part you can take a look at the code repositoryimport useUser from lib hooks user import signIn from next auth react import FormEvent useState from react export default function Signup const email setEmail useState const password setPassword useState const create signup useUser async function onSignup e FormEvent lt HTMLFormElement gt e preventDefault try await signup data email password catch err any if err info prisma true if err info code P alert User already exists else alert Unexpected Prisma error err info code as string else alert Error occurred JSON stringify err return const signInResult await signIn credentials redirect false email password if signInResult ok window location href else console error Signin failed signInResult error html return Conceptually signup is to create a user So the same applies to the code singup is the create hook of User ZenStack generated for you Sign inlet s create a sign in page under src pages singin tsximport signIn from next auth react import Link from next link import useRouter from next router import FormEvent useEffect useState from react export default function Signin const email setEmail useState const password setPassword useState const router useRouter async function onSignin e FormEvent lt HTMLFormElement gt e preventDefault const signInResult await signIn credentials redirect false email password if signInResult ok window location href else alert Signin failed Please check your email and password html return The sign in part is still the same as you always do use NextAuth Now you can do the sign up sign in as below Let s create the first user admin zenstack com Home page Show spacesThe most important thing we need to show on the home page is the spaces this user belongs to So let s change the src index tsx import Space from prisma client import Spaces from components Spaces import WithNavBar from components WithNavBar import type GetServerSideProps NextPage from next import Link from next link import getEnhancedPrisma from server enhanced db import useCurrentUser from lib context import useSession from next auth react import useRouter from next router type Props spaces Space const Home NextPage lt Props gt spaces gt const user useCurrentUser const router useRouter const status useSession if status unauthenticated void router push signin return lt gt lt gt return lt WithNavBar gt user amp amp lt div className mt flex w full flex col items center text center gt lt h className text xl text gray gt Welcome user name user email lt h gt lt div className w full p gt lt h className mb text left text lg text gray md text xl gt Choose a space to start or lt Link className link primary underline href create space gt create a new one lt Link gt lt h gt lt Spaces spaces spaces gt lt div gt lt div gt lt WithNavBar gt export const getServerSideProps GetServerSideProps lt Props gt async ctx gt const db await getEnhancedPrisma ctx const spaces await db space findMany return props spaces export default Home Without ZenStack normally to get the result you will need manually write the filter as below const session await getServerAuthSession ctx const spaces await db space findMany where members some userId session user id With ZenStack you can simply query all the spaces as await db space findMany That s the beauty of ZenStack when you write the query logic you don t need to worry about access control at all You will write as if there is no such thing and ZenStack will take care of it as it s defined in the schema Space Home PageEach space will have a unique URL including its slug so let s create the page for it under src pages space slug index tsximport Space from prisma client import BreadCrumb from components BreadCrumb import SpaceMembers from components SpaceMembers import WithNavBar from components WithNavBar import GetServerSideProps from next import useRouter from next router import getEnhancedPrisma from server enhanced db type Props space Space export default function SpaceHome props Props const router useRouter return lt WithNavBar gt lt div className px py gt lt BreadCrumb space props space gt lt div gt lt div className p gt lt div className w full flex flex col md flex row mb space y md space y md space x gt lt SpaceMembers gt lt div gt lt div gt lt WithNavBar gt export const getServerSideProps GetServerSideProps lt Props gt async req res params gt const db await getEnhancedPrisma req res const space await db space findUnique where slug params slug as string if space return notFound true return props space Like the home page it simply queries the space using slug as the only filter regardless of the access policy If the space can t be found it does not necessarily indicate that the space does not exist It is possible that you are not authorized to access it Create SpaceCreating space is similar to creating a user Let s create src pages create space tsx for it import useSpace from lib hooks import SpaceUserRole from prisma client import WithNavBar from components WithNavBar import NextPage from next import useSession from next auth react import useRouter from next router import FormEvent useState from react const CreateSpace NextPage gt const data session useSession const name setName useState const slug setSlug useState const create useSpace const router useRouter const onSubmit async event FormEvent gt event preventDefault try const space await create data name slug members create userId session user id role SpaceUserRole ADMIN alert Space created successfull You ll be redirected setTimeout gt if space void router push space space slug catch err any console error err if err info prisma true if err info code P alert Space slug already in use else alert Unexpected Prisma error err info code as string else alert JSON stringify err html return export default CreateSpace Now let s create the new space “ZenStack Team after which it will redirect to the team space with the space URL http localhost space zenstack If you go back to the home page you will see the ZenStack team Team managementLet s create the team management dialog under src components ManageMembers tsximport PlusIcon TrashIcon from heroicons react outline import useCurrentUser from lib context import useSpaceUser from lib hooks import Space SpaceUserRole from prisma client import ChangeEvent KeyboardEvent useState from react import Avatar from Avatar type Props space Space export default function ManageMembers space Props const email setEmail useState const role setRole useState lt SpaceUserRole gt SpaceUserRole USER const user useCurrentUser const findMany create addMember del delMember useSpaceUser const data members findMany where spaceId space id include user true orderBy role desc const inviteUser async gt try const r await addMember data user connect email space connect id space id role console log SpaceUser created r catch err any console error err if err info prisma true if err info code P alert User is already a member of the space else if err info code P alert User is not found for this email else alert Unexpected Prisma error err info code as string else alert Error occurred JSON stringify err const removeMember async id string gt if confirm Are you sure to remove this member from space await delMember where id html return The dialog would look like below All done You can see there is no actual code logic handling the access control but let s see whether it is there TestRemember our friend Bob let s create an account for him with bob gmail com and create a space as Bob s Family Then let s invite bob to ZenStack s space as a USER Then Bob will see ZenStack s space on his home page Although Bob s a USER who cannot manage the team member according to the access control defined in the schema we don t make that restriction from UI Let s try to remove admin zenstack com to see what will happen After confirmation nothing really happens which means the removal operation doesn t succeed Open the developer tool of the browser you can see a message below with the message body prisma true rejectedByPolicy true code P message denied by policy spaceUser entities failed delete check entities failed policy check You can try to add a new user you will see a similar result Therefore the API is indeed secured by access control Now Bob could access ZenStack s team space home page by accessing its URL http localhost space zenstack Let s remove Bob from ZenStack s team space using admin zenstack com Then let s access that page again you will see the page now ConclusionI hope this tutorial can show you the benefit of ZenStack in using the data model as the single source of truth to handle access control Feel free to contact us on our Discord or GitHub if you have any questions about it 2023-02-05 09:57:19
海外TECH DEV Community Dockerize and deploy🚀 your Angular App with a secure endpoint 🔐(HTTPS) using ChatGPT3🤖 https://dev.to/wi11i4m/dockerize-and-deploy-your-angular-app-with-a-secure-endpoint-https-using-chatgpt3-12d0 Dockerize and deployyour Angular App with a secure endpoint HTTPS using ChatGPTFirst of all I ll explain to you how to do that without ChatGPT and after I ll give you some commands that you can use in ChatGPT to do it Part Dockerize your angular application Create a Dockerfile in your angular project Stage FROM node alpine AS buildWORKDIR appCOPY package json package lock json RUN npm ciCOPY RUN npm run build prod Stage FROM nginx alpine add permissions for nginx userRUN chown R nginx nginx var cache nginx amp amp chown R nginx nginx var log nginx amp amp chown R nginx nginx etc nginx conf dRUN touch var run nginx pid amp amp chown R nginx nginx var run nginx pid switch to nginx user USER nginxCOPY from build app dist weather app usr share nginx htmlCMD nginx g daemon off ExplanationWe use a dockerfile with stages the first one to build our angular applicationthe second is to make an image of our angular app from an Nginx imageWORKDIR app navigate to app foldernpm ci npm clean install Best practicesAs a best practice we re building our image from an alpine version of Nginx to get the smaller size possible for our image We re also using a non root user to minimalize the privilege in our container The multi stage Dockerfile allows us to build an image without the useless heavy package used to build our application Run the following commands to build and push your image docker build t DOCKERHUB USERNAME weather app docker login u DOCKERHUB USERNAME p DOCKERHUB PASSWORDdocker push DOCKERHUB USERNAME weather app Part Create a VPS and a domain nameCreate a virtual machine instance on AWS for free with the ubuntu os and instance type t microDownload the private key of your instance and run the command ssh i PRIVATE KEY FILE NAME pem ubuntu VM PUBLIC IPAnd create a domain name for your application for free on No IP and link it to the public IP of your VPS Part Deploy your application Create a docker compose file in your VPSversion services weather app container name weather app image wiim weather app ports environment VIRTUAL HOST weather app ddns net LETSENCRYPT HOST weather app ddns net nginx proxy container name nginx proxy image jwilder nginx proxy alpine ports environment DHPARAM GENERATION false disable auto param generation volumes var run docker sock tmp docker sock ro allow nginx to interact with docker etc nginx certs etc nginx certs certificate etc nginx vhost d etc nginx vhost d host nginx proxy html usr share nginx html store our web app nginx proxy letencrypt container name nginx proxy letsencrypt image jrcs letsencrypt nginx proxy companion volumes var run docker sock var run docker sock ro allow nginx to interact with docker etc nginx certs etc nginx certs certificate etc nginx vhost d etc nginx vhost d host nginx proxy html usr share nginx html store our web app environment DEFAULT EMAIL example gmail com NGINX PROXY CONTAINER nginx proxyvolumes nginx proxy html Replace wiim weather app with your docker image and example ddns net with the domain name you just created Run the docker compose file by using docker compose up dAfter that you can visit your app by using your domain nameIf you get the page doesn t load verify that you allowed port HTTPS on your VPS 2023-02-05 09:36:28
海外TECH DEV Community Single responsibility in Javascript https://dev.to/emhat098/single-responsibility-in-javascript-54j8 Single responsibility in Javascript IntroductionThere should never be more than one reason for a class to change That mean each class or object should have one responsibility to do something ContentWe look at the example below function Question questions this questions questions this printReport gt console log Printer called console log th party printer function called this saveDatabase questions gt console log questions console log Saved to database this remove question gt console log removed question question this questions this questions filter q gt q question this saveDatabase this questions this add question gt console log added question this questions push question this saveDatabase this questions const q new Question Question Question Question Question q remove Question q printReport q add Question q printReport The purpose of Question object is process the questions as save list out remove question and also printing In this approach the problem that is the printReport saveDatabase remove function and also the mechanism log of the system console log In the context we change the method saveDatabase from Postgres to MongoDB so we are going to change all the function of objects reference to save the data method The printReport remove and console log are the same like that So to easily maintain and re factory in the later The mission of SRP breaks the application into small pieces and each piece should have a mission to do something I think Now look at the new code below function printer data console log th party function called log new Date toLocaleString log data info function log message type log console type message function saveDatabase data log data info log Saved data to database info function Question questions this questions questions this printReport gt printer this questions this remove question gt log removed question question this questions this questions filter q gt q question saveDatabase this questions this add question gt log added question this questions push question saveDatabase this questions const q new Question Question Question Question Question q remove Question q printReport q add Question q printReport The printReport saveDatabase log functions moved to other objects implement the remove method So now every function just does one thing If each function changes the logic we only go to this function and do change logic based on another requirement without modifying other functions which used them and prevent the unexpected bugger SummaryThe Single Responsibility Principle is a great principle to create an application We are easy to maintain implement and prevents unexpected side effects of feature changes to system Thank you for reading Have a great day 2023-02-05 09:10:26
海外科学 BBC News - Science & Environment How beavers are reviving wetlands https://www.bbc.co.uk/news/science-environment-64502365?at_medium=RSS&at_campaign=KARANGA beavers 2023-02-05 09:50:56
海外ニュース Japan Times latest articles The Winter Olympics have a climate problem. Could Sapporo be part of the solution? https://www.japantimes.co.jp/news/2023/02/05/national/science-health/sapporo-winter-olympics-climate-change/ The Winter Olympics have a climate problem Could Sapporo be part of the solution Sapporo is touting a study showing that among all past hosts it will be the most climate resilient as the planet warms But residents are 2023-02-05 18:25:23
海外ニュース Japan Times latest articles Kishida fires senior aide over homophobic comments https://www.japantimes.co.jp/news/2023/02/05/national/politics-diplomacy/masayoshi-arai-japan-same-sex-marriage-hate/ commentsmasayoshi 2023-02-05 18:02:21
ニュース BBC News - Home Ofgem had wool pulled over its eyes on prepayment meters issue, says Grant Shapps https://www.bbc.co.uk/news/uk-64526939?at_medium=RSS&at_campaign=KARANGA energy 2023-02-05 09:01:34

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)