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

商业网站建设费用网络建设费用

商业网站建设费用,网络建设费用,怎么给网站做404界面,简单网页制作模板源代码文章目录 一、介绍二、auth微服务代码1. SecurityConfig2. UserDetailsService3. 总结 三、gateway微服务代码1. 统一处理CORS问题 四、content微服务代码1. controller2. SecurityConfig3. 解析JWT Utils4. 总结 五、一些坑 书接上文 微服务OAuth 2.1认证授权可行性方案(Sprin… 文章目录 一、介绍二、auth微服务代码1. SecurityConfig2. UserDetailsService3. 总结 三、gateway微服务代码1. 统一处理CORS问题 四、content微服务代码1. controller2. SecurityConfig3. 解析JWT Utils4. 总结 五、一些坑 书接上文 微服务OAuth 2.1认证授权可行性方案(Spring Security 6) 一、介绍 三个微服务 auth微服务作为认证服务器用于颁发JWT。gateway微服务作为网关用于拦截过滤。content微服务作为资源服务器用于校验授权。 以下是授权相关数据库。 user表示用户表role表示角色表user_role关联了用户和角色表示某个用户是是什么角色。一个用户可以有多个角色menu表示资源权限表。PreAuthorize(hasAuthority(xxx))时用的就是这里的code。permission关联了角色和资源权限表示某个角色用于哪些资源访问权限一个角色有多个资源访问权限。 当我们知道userId我们就可以知道这个用户可以访问哪些资源并把这些权限也就是menu里的code字段写成数组写到JWT的负载部分的authorities字段中。当用户携带此JWT访问具有PreAuthorize(hasAuthority(xxx))修饰的资源时我们解析出JWT中的authorities字段判断是否包含hasAuthority指定的xxx权限以此来完成所谓的的“授权”。 二、auth微服务代码 1. SecurityConfig package com.xuecheng.auth.config;import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.source.ImmutableJWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.http.MediaType; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.oidc.OidcScopes; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; import org.springframework.security.oauth2.server.authorization.settings.TokenSettings; import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.time.Duration; import java.util.List; import java.util.UUID; import java.util.stream.Collectors;/*** 身份验证服务器安全配置** author mumu* date 2024/02/13*/ //EnableGlobalMethodSecurity(securedEnabled true, prePostEnabled true) Configuration EnableWebSecurity public class AuthServerSecurityConfig {private static KeyPair generateRsaKey() {KeyPair keyPair;try {KeyPairGenerator keyPairGenerator KeyPairGenerator.getInstance(RSA);keyPairGenerator.initialize(2048);keyPair keyPairGenerator.generateKeyPair();} catch (Exception ex) {throw new IllegalStateException(ex);}return keyPair;}/*** 密码编码器* 用于加密认证服务器client密码和用户密码** return {link PasswordEncoder}*/Beanpublic PasswordEncoder passwordEncoder() {// 密码为明文方式// return NoOpPasswordEncoder.getInstance();// 或使用 BCryptPasswordEncoderreturn new BCryptPasswordEncoder();}/*** 授权服务器安全筛选器链* br/* 来自Spring Authorization Server示例用于暴露Oauth2.1端点一般不影响常规的请求** param http http* return {link SecurityFilterChain}* throws Exception 例外*/BeanOrder(1)public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)throws Exception {OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);http.getConfigurer(OAuth2AuthorizationServerConfigurer.class).oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0http// Redirect to the login page when not authenticated from the// authorization endpoint.exceptionHandling((exceptions) - exceptions.defaultAuthenticationEntryPointFor(new LoginUrlAuthenticationEntryPoint(/login),new MediaTypeRequestMatcher(MediaType.TEXT_HTML)))// Accept access tokens for User Info and/or Client Registration.oauth2ResourceServer((resourceServer) - resourceServer.jwt(Customizer.withDefaults()));return http.build();}/*** 默认筛选器链* br/* 这个才是我们需要关心的过滤链可以指定哪些请求被放行哪些请求需要JWT验证** param http http* return {link SecurityFilterChain}* throws Exception 例外*/BeanOrder(2)public SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests((authorize) -authorize.requestMatchers(new AntPathRequestMatcher(/actuator/**)).permitAll().requestMatchers(new AntPathRequestMatcher(/login)).permitAll().requestMatchers(new AntPathRequestMatcher(/logout)).permitAll().requestMatchers(new AntPathRequestMatcher(/wxLogin)).permitAll().requestMatchers(new AntPathRequestMatcher(/register)).permitAll().requestMatchers(new AntPathRequestMatcher(/oauth2/**)).permitAll().requestMatchers(new AntPathRequestMatcher(/**/*.html)).permitAll().requestMatchers(new AntPathRequestMatcher(/**/*.json)).permitAll().requestMatchers(new AntPathRequestMatcher(/auth/**)).permitAll().anyRequest().authenticated()).csrf(AbstractHttpConfigurer::disable)//指定logout端点用于退出登陆不然二次获取授权码时会自动登陆导致短时间内无法切换用户.logout(logout - logout.logoutUrl(/logout).addLogoutHandler(new SecurityContextLogoutHandler()).logoutSuccessUrl(http://www.51xuecheng.cn)).formLogin(Customizer.withDefaults()).oauth2ResourceServer(oauth2 - oauth2.jwt(Customizer.withDefaults()) // .jwt(jwt - jwt // .jwtAuthenticationConverter(jwtAuthenticationConverter()) // ));return http.build();}private JwtAuthenticationConverter jwtAuthenticationConverter() {JwtAuthenticationConverter jwtConverter new JwtAuthenticationConverter();return jwtConverter;}/*** 客户端管理实例* br/* 来自Spring Authorization Server示例** return {link RegisteredClientRepository}*/Beanpublic RegisteredClientRepository registeredClientRepository() {RegisteredClient registeredClient RegisteredClient.withId(UUID.randomUUID().toString()).clientId(XcWebApp).clientSecret(passwordEncoder().encode(XcWebApp)).clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).redirectUri(http://www.51xuecheng.cn).redirectUri(http://localhost:63070/auth/wxLogin).redirectUri(http://www.51xuecheng.cn/sign.html) // .postLogoutRedirectUri(http://localhost:63070/login?logout).scope(all).scope(OidcScopes.OPENID).scope(OidcScopes.PROFILE).scope(message.read).scope(message.write).scope(read).scope(write).clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()).tokenSettings(TokenSettings.builder().accessTokenTimeToLive(Duration.ofHours(2)) // 设置访问令牌的有效期.refreshTokenTimeToLive(Duration.ofDays(3)) // 设置刷新令牌的有效期.reuseRefreshTokens(true) // 是否重用刷新令牌.build()).build();return new InMemoryRegisteredClientRepository(registeredClient);}/*** jwk源* br/* 对访问令牌进行签名的示例里面包含公私钥信息。** return {link JWKSource}{link SecurityContext}*/Beanpublic JWKSourceSecurityContext jwkSource() {KeyPair keyPair generateRsaKey();RSAPublicKey publicKey (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey (RSAPrivateKey) keyPair.getPrivate();RSAKey rsaKey new RSAKey.Builder(publicKey).privateKey(privateKey).keyID(UUID.randomUUID().toString()).build();JWKSet jwkSet new JWKSet(rsaKey);return new ImmutableJWKSet(jwkSet);}/*** jwt解码器* br/* JWT解码器主要就是基于公钥信息来解码** param jwkSource jwk源* return {link JwtDecoder}*/Beanpublic JwtDecoder jwtDecoder(JWKSourceSecurityContext jwkSource) {return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);}Beanpublic AuthorizationServerSettings authorizationServerSettings() {return AuthorizationServerSettings.builder().build();}/*** JWT定制器* BR/* 可以往JWT从加入额外信息这里是加入authorities字段是一个权限数组。** return {link OAuth2TokenCustomizer}{link JwtEncodingContext}*/Beanpublic OAuth2TokenCustomizerJwtEncodingContext jwtTokenCustomizer() {return context - {Authentication authentication context.getPrincipal();if (authentication.getPrincipal() instanceof UserDetails userDetails) {ListString authorities userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());context.getClaims().claim(authorities, authorities);}};} }这里需要注意几点 使用BCryptPasswordEncoder密码加密在设置clientSecret时需要手动使用密码编码器。jwtTokenCustomizer解析UserDetails然后往JWT中添加authorities字段为了后面的授权。 2. UserDetailsService package com.xuecheng.ucenter.service.impl;import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.xuecheng.ucenter.mapper.XcMenuMapper; import com.xuecheng.ucenter.mapper.XcUserMapper; import com.xuecheng.ucenter.model.dto.AuthParamsDto; import com.xuecheng.ucenter.model.dto.XcUserExt; import com.xuecheng.ucenter.model.po.XcMenu; import com.xuecheng.ucenter.model.po.XcUser; import com.xuecheng.ucenter.service.AuthService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component;import java.util.Arrays; import java.util.List; import java.util.stream.Collectors;Component Slf4j public class UserServiceImpl implements UserDetailsService {Autowiredprivate MyAuthService myAuthService;AutowiredXcMenuMapper xcMenuMapper;/*** 用户统一认证** param s 用户信息Json字符串* return {link UserDetails}* throws UsernameNotFoundException 找不到用户名异常*/Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {XcUserExt xcUserExt myAuthService.execute(username);return getUserPrincipal(xcUserExt);}public UserDetails getUserPrincipal(XcUserExt user){//用户权限,如果不加报Cannot pass a null GrantedAuthority collectionListXcMenu xcMenus xcMenuMapper.selectPermissionByUserId(user.getId());String[] permissions {read};if (ObjectUtils.isNotEmpty(xcMenus)){permissions xcMenus.stream().map(XcMenu::getCode).toList().toArray(String[]::new);log.info(权限如下:{}, Arrays.toString(permissions));}//为了安全在令牌中不放密码String password user.getPassword();user.setPassword(null);//将user对象转jsonString userString JSON.toJSONString(user);//创建UserDetails对象return User.withUsername(userString).password(password).authorities(permissions).build();} } 这里需要注意几点 username就是前端/auth/login的时候输入的账户名。myAuthService.execute(username)不抛异常就默认表示账户存在此时将password加入UserDetails 并返回Spring Authorization Server对比校验两个密码。myAuthService.execute(username)根据username获取用户信息返回将用户信息存入withUsername中Spring Authorization Server默认会将其加入到JWT中。现在Spring Authorization Server默认不会把authorities(permissions)写入JWT需要配合OAuth2TokenCustomizer手动写入。 3. 总结 这样auth微服务颁发的JWT现在就会包含authorities字段。示例如下 {active: true,sub: {\cellphone\:\17266666637\,\createTime\:\2024-02-13 10:33:13\,\email\:\1138882663qq.com\,\id\:\012f3a90-2bc9-4a2c-82a3-f9777c9ac10a\,\name\:\xiamu\,\nickname\:\xiamu\,\permissions\:[],\status\:\1\,\updateTime\:\2024-02-13 10:33:13\,\username\:\xiamu\,\utype\:\101001\,\wxUnionid\:\test\},aud: [XcWebApp],nbf: 1707830437,scope: all,iss: http://localhost:63070/auth,exp: 1707837637,iat: 1707830437,jti: 8a657c60-968f-4d98-8a4c-22a7b4ecd333,authorities: [xc_sysmanager,xc_sysmanager_company,xc_sysmanager_doc,xc_sysmanager_log,xc_teachmanager_course_list],client_id: XcWebApp,token_type: Bearer }三、gateway微服务代码 1. 统一处理CORS问题 EnableWebFluxSecurity Configuration public class SecurityConfig {//安全拦截配置Beanpublic SecurityWebFilterChain webFluxSecurityFilterChain(ServerHttpSecurity http) throws Exception {return http.cors(cors - cors.configurationSource(corsConfigurationSource())).authorizeExchange(exchanges -exchanges.pathMatchers(/**).permitAll().anyExchange().authenticated()).oauth2ResourceServer(oauth2 - oauth2.jwt(Customizer.withDefaults())).csrf(ServerHttpSecurity.CsrfSpec::disable).build();}Beanpublic CorsConfigurationSource corsConfigurationSource() {CorsConfiguration corsConfig new CorsConfiguration();corsConfig.addAllowedOriginPattern(*); // 允许任何源corsConfig.addAllowedMethod(*); // 允许任何HTTP方法corsConfig.addAllowedHeader(*); // 允许任何HTTP头corsConfig.setAllowCredentials(true); // 允许证书cookiescorsConfig.setMaxAge(3600L); // 预检请求的缓存时间秒UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration(/**, corsConfig); // 对所有路径应用这个配置return source;} } 这里需要注意几点 书接上文这里虽然用了oauth2.jwt(Customizer.withDefaults())但实际上基于远程auth微服务开放的jwkSetEndpoint配置的JwtDecoder。.cors(cors - cors.configurationSource(corsConfigurationSource()))一次性处理CORS问题。 四、content微服务代码 1. controller PreAuthorize(hasAuthority(xc_teachmanager_course_list))ApiResponse(responseCode 200, description Successfully retrieved user)Operation(summary 查询课程信息列表)PostMapping(/course/list)public PageResultCourseBase list(PageParams pageParams,Parameter(description 请求具体内容) RequestBody(required false) QueryCourseParamsDto dto){SecurityUtil.XcUser xcUser SecurityUtil.getUser();if (xcUser ! null){System.out.println(xcUser.getUsername());System.out.println(xcUser.toString());}return courseBaseInfoService.queryCourseBaseList(pageParams, dto);}使用了PreAuthorize(hasAuthority(xc_teachmanager_course_list))修饰的controller资源。 2. SecurityConfig Configuration EnableWebSecurity EnableMethodSecurity public class SecurityConfig {//安全拦截配置Beanpublic SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests((authorize) -authorize.requestMatchers(/**).permitAll().anyRequest().authenticated()).csrf(AbstractHttpConfigurer::disable).oauth2ResourceServer(oauth - oauth.jwt(jwt - jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())));return http.build();}private JwtAuthenticationConverter jwtAuthenticationConverter() {JwtAuthenticationConverter jwtConverter new JwtAuthenticationConverter();jwtConverter.setJwtGrantedAuthoritiesConverter(jwt - {// 从JWT的claims中提取权限信息ListString authorities jwt.getClaimAsStringList(authorities);if (authorities null) {return Collections.emptyList();}return authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());});return jwtConverter;} }需要注意几点 使用EnableMethodSecurity让PreAuthorize生效和gateway一样需要基于远程auth微服务开放的jwkSetEndpoint配置JwtDecoder。指定JwtAuthenticationConverter 让anyRequest().authenticated()需要验证的请求除了完成默认的JWT验证外还需要完成JwtAuthenticationConverter 指定逻辑。JwtAuthenticationConverter 中将JWT的authorities部分形成数组后写入GrantedAuthorities这正是spring security6用于校验PreAuthorize的字段。 3. 解析JWT Utils Slf4j public class SecurityUtil {public static XcUser getUser(){Authentication authentication SecurityContextHolder.getContext().getAuthentication();if (authentication null){return null;}if (authentication instanceof JwtAuthenticationToken) {JwtAuthenticationToken jwtAuth (JwtAuthenticationToken) authentication;System.out.println(jwtAuth);MapString, Object tokenAttributes jwtAuth.getTokenAttributes();System.out.println(tokenAttributes);Object sub tokenAttributes.get(sub);return JSON.parseObject(sub.toString(), XcUser.class);}return null;}Datapublic static class XcUser implements Serializable {private static final long serialVersionUID 1L;private String id;private String username;private String password;private String salt;private String name;private String nickname;private String wxUnionid;private String companyId;/*** 头像*/private String userpic;private String utype;private LocalDateTime birthday;private String sex;private String email;private String cellphone;private String qq;/*** 用户状态*/private String status;private LocalDateTime createTime;private LocalDateTime updateTime;} }把JWT的信息解析回XcUser 相当于用户携带JWT访问后端后端可以根据JWT获取此用户的信息。当然你可以尽情的自定义扩展。 4. 总结 当用户携带JWT访问需要权限的资源时现在可以正常的校验权限了。 五、一些坑 写RegisteredClient时注册那么多redirectUri是因为debug了很久才发现获取授权码和获取JWT时redirect_uri参数需要一致。cors问题spring secuity6似乎会一开始直接默认拒绝cors导致跨域请求刚到gateway就寄了到不了content微服务即使content微服务配置了CORS的处理方案也无济于事。
http://www.w-s-a.com/news/856380/

相关文章:

  • 建外贸网站 东莞厦门做网站最好的公司
  • 为您服务网站新网站做百度推广
  • 电子商务免费网站建设网站制作哪个好薇
  • 全面启动门户网站建设中小型企业建设一个网站大概需要多少钱
  • 建网站一般多少钱网站建设上传服务器步骤
  • 手机销售网站怎么做的网站推广优化建设方案
  • 做任务分享赚钱的网站德阳网站建设公司哪家好
  • 云南建设工程质量监督网站wordpress网站导航主题
  • 徐州网站建设哪家好薇手机开源网站代码
  • 更新网站要怎么做呢泰安市58同城招聘网
  • 溧阳网站建设价格企业网站设计费用
  • 我建设的网站打开很慢河北住房和城乡建设厅网站卡
  • 门户网站广告的特点有网站的建设初步定位
  • 建设网站第一步网页建设方案
  • 网站开发需要那些人才wordpress 小工具原理
  • 广州建设局官方网站佛山高端网站制作公司
  • 东莞哪里能学建设网站网站备案值得吗
  • 中山 网站建设 骏域小程序开发课程
  • 北京网站建设成都微商城app官方下载
  • 网站开发用户登陆的安全wordpress 开发网站
  • 网站建设容易出现的问题四川seo关键词工具
  • 做外单网站有哪些内容服务好的南京网站建设
  • 阜阳微商城网站建设百度网站两两学一做心得体会
  • 建设银行积分网站观光农业规划设计
  • jsp项目个人网站开发用织梦做网站有什么公司会要
  • 和田网站制作无限动力网站
  • 长沙口碑好网站建设企业网站 需求
  • 哪个网站建设公司wordpress陌陌主题
  • 湖滨区建设局网站北京国际建设集团网站
  • 做服装团购有哪些网站wordpress 端口修改