Oauth2+jwt+redis+cookie+springsecurity+springboot+springcloud(用户登录认证授权)

2023-10-28

  1. 用户认证分析
    1). 单点登录
    一处登录 , 处处运行 ;
    SSO —> Single Sign On
    作用:
    A. 解决集群环境下的登录问题 ;
    B. 解决多套互信的系统之间的登录问题 ; ----------> 天猫 , 淘宝 , 天猫超市 , 天猫国际 ;

2). 第三方登录
QQ登录
微博登录
微信登录

  1. 认证解决方案
    1). 单点登录流程
    在这里插入图片描述

2). 第三方登录
第三方登录基本上都采用的是 Oauth2 协议 ;

Oauth2.0 流程:
在这里插入图片描述

3). 前端系统用户认证流程
技术点: SpringSecurity + Jwt + Redis + Oauth2

在这里插入图片描述

4.2 生成私钥和公钥
A. 生成秘钥证书(存储了私钥和公钥)
keytool -genkeypair -alias changgou -keyalg RSA -keypass changgou -keystore changgou.jks -storepass changgou

在这里插入图片描述

B. 获取公钥
keytool -list -rfc --keystore changgou.jks | openssl x509 -inform pem -pubkey
4.3 认证服务导入

在这里插入图片描述

4.4 基于私钥生成JWT令牌

@Test
public void createJWT(){
//基于私钥生成jwt
//1. 创建一个秘钥工厂
//1: 指定私钥的位置
ClassPathResource classPathResource = new ClassPathResource(“changgou.jks”);
//2: 指定秘钥库的密码
String keyPass = “changgou”;
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(classPathResource,keyPass.toCharArray());

//2. 基于工厂获取私钥
String alias = "changgou";
String password = "changgou";
KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias, password.toCharArray());
//将当前的私钥转换为rsa私钥
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();


//3.生成jwt
Map<String,String> map = new HashMap();
map.put("company","heima");
map.put("address","beijing");// 自定义内容

Jwt jwt = JwtHelper.encode(JSON.toJSONString(map), new RsaSigner(rsaPrivateKey));
String jwtEncoded = jwt.getEncoded();
System.out.println(jwtEncoded);

}

4.5 基于公钥校验JWT令牌
String jwt = “…”;
String publicKey="…";
Jwt token = JwtHelper.decodeAndVerify(jwt, new RsaVerifier(publicKey));
String claims = token.getClaims();

注意 : 公钥和私钥是成对生成的 ;
1、用户请求认证服务完成认证。
2、认证服务下发用户身份令牌,拥有身份令牌表示身份合法。
3、用户携带令牌请求资源服务,请求资源服务必先经过网关。
4、网关校验用户身份令牌的合法,不合法表示用户没有登录,如果合法则放行继续访问。
5、资源服务获取令牌,根据令牌完成授权。
6、资源服务完成授权则响应资源信息。

在这里插入图片描述

  1. Oauth2入门
    1.1 准备工作
    oauth_client_details 表结构;
    1.2 授权码模式
    1.2.1 获取授权码
    访问获取授权码的URL :
    http://localhost:9200/oauth/authorize?client_id=changgou&response_type=code&scop=app&redirect_uri=http://localhost

在这里插入图片描述
在这里插入图片描述
返回授权码 :
http://localhost/?code=50E3uL
1.2.2 获取令牌
URL :
POST http://localhost:9200/oauth/token
参数 :
A. 认证参数

在这里插入图片描述
B. form表单参数

在这里插入图片描述
在这里插入图片描述

grant_type : authorization_code -------> 模式
code : 50E3uL----------------------------> 授权码
redirect_uri : http://localhost ---------> 申请授权码时重定向的连接
获取到的令牌JSON格式 :

{
	"access_token": xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,
	"token_type" : xxx,
	"refresh_token" :xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,
	"jti":xxxxxxxxxxxxxxxx,
	"expires_in":43199
}

jti : 短令牌 ; 一个jti 对应于一个access_token ;
access_token : JWT令牌 ;
1.2.3 校验刷新令牌
1). 校验
GET http://localhost:9200/oauth/check_token?token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

在这里插入图片描述

2). 刷新
申请到的JWT令牌是有有效期的 , 当jwt令牌快过期时, 可以通过refresh_token 刷新令牌 , 重置过期时间 ;
POST http://localhost:9200/oauth/token

参数 :
grant_type refresh_token
refresh_token xxxxxxxxxxxxxxxxxxxxxx

在这里插入图片描述

1.3 密码模式
POST http://localhost:9200/oauth/token

参数 :
1). 认证参数
在这里插入图片描述

username 实际上指ClientId
password 实际上指ClientSecret
2). form表单参数
在这里插入图片描述
区分 clientId 与 Username :
在这里插入图片描述

默认配置 , 用户名密码时写死的
1.4 资源服务接入认证

1、客户端请求认证服务申请令牌
2、认证服务生成令牌认证服务采用非对称加密算法,使用私钥生成令牌。
3、客户端携带令牌访问资源服务客户端在Http header 中添加: Authorization:Bearer令牌。
4、资源服务请求认证服务校验令牌的有效性资源服务接收到令牌,使用公钥校验令牌的合法性。
5、令牌有效,资源服务向客户端响应资源信息
1). 引入依赖

org.springframework.cloud
spring-cloud-starter-oauth2

2). 引入公钥 public.key
3). 引入配置类
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的 @PreAuthorize 注解
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

//公钥
private static final String PUBLIC_KEY = "public.key";

/***
 * 定义JwtTokenStore
 * @param jwtAccessTokenConverter
 * @return
 */
@Bean
public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
    return new JwtTokenStore(jwtAccessTokenConverter);
}

/***
 * 定义JJwtAccessTokenConverter
 * @return
 */
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setVerifierKey(getPubKey());
    return converter;
}
/**
 * 获取非对称加密公钥 Key
 * @return 公钥 Key
 */
private String getPubKey() {
    Resource resource = new ClassPathResource(PUBLIC_KEY);
    try {
        InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
        BufferedReader br = new BufferedReader(inputStreamReader);
        return br.lines().collect(Collectors.joining("\n"));
    } catch (IOException ioe) {
        return null;
    }
}
/***
 * Http安全配置,对每个到达系统的http请求链接进行校验
 * @param http
 * @throws Exception
 */
@Override
public void configure(HttpSecurity http) throws Exception {
    //所有请求必须认证通过
    http.authorizeRequests()
            //下边的路径放行
            .antMatchers(
                    "/user/add","/user/load/**"). //配置地址放行
            permitAll()
            .anyRequest().
            authenticated();    //其他地址需要认证授权
}

}

携带令牌(Header —> Authorization)访问资源服务 :

在这里插入图片描述
2. 认证接口开发
2.1 认证流程
在这里插入图片描述

2.2 申请令牌测试
通过java程序, 申请令牌 (将postman中的申请令牌的接口调用, 改为java代码实现)
步骤 :
1). 组装申请令牌的URL ;
2). 组装申请令牌所需要的参数 ;
3). 错误码的处理 ;
4). 发送请求, 获取结果 ;

@SpringBootTest
@RunWith(SpringRunner.class)
public class ApplyTokenTest {

/**
 * 通过负载均衡的方式获取指定服务的实例对象
 */
@Autowired
private LoadBalancerClient loadBalancerClient;

@Autowired
private RestTemplate restTemplate;
@Test
public void applyTest(){
    // 1). 组装申请令牌的URL ;  构建请求地址  http://localhost:9200/oauth/token
    // 1.1获取user-auth 的服务实例对象
    ServiceInstance serviceInstance = loadBalancerClient.choose("user-auth");
    // 1.2通过负载均衡的方式获取uri
    URI uri = serviceInstance.getUri();
    String url = uri + "/oauth/token";

    // 2). 组装申请令牌所需要的参数 ;
    // 2.1 第一个参数 请求体的构建
    MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
    body.add("grant_type","password");
    body.add("username","itheima");
    body.add("password","itheima");
    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    // 2.2 第二个参数,请求头的构建 调用自定义的私有方法,将String clientId, String clientSecret 进行封装
    headers.add("Authorization",this.getHttpBasic("changgou","changgou"));
    HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity<>(body,headers);
    // 3). 错误码的处理 ;
    //当后端出现了401,400.后端不对着两个异常编码进行处理,而是直接返回给前端 --
    restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
        @Override
        public void handleError(ClientHttpResponse response) throws IOException {
            // 如果不是401 或者400的错误,才处理
            if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401){
                super.handleError(response);
            }
        }
    });
    // 4). 发送请求, 获取结果 ;
    /**
     * 第一个参数 请求的url
     * 第二个参数 请求的方式
     *  第三个参数封装请求的参数
     */
    ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);

    Map map = responseEntity.getBody();
    System.out.println(map);
}

private String getHttpBasic(String clientId, String clientSecret) {
    // 2.3http Basic认证 时将消息转换为 Authorization :Basic Y2hhbmdnb3U6Y2hhbmdnb3U=
    String value = clientId + ":" + clientSecret;
    // 2.4 然后将内容进行base64加密
    byte[] encode = Base64Utils.encode(value.getBytes());
    return "Basic " + new String(encode);

}

}

2.3 认证接口业务层实现
步骤 :
1). 申请令牌 ;
2). 组装令牌数据 ;
3). 往redis中存储令牌 ;

代码实现:
@Service
public class AuthServiceImpl implements AuthService {

@Autowired
private RestTemplate restTemplate;

@Autowired
private LoadBalancerClient loadBalancerClient;

@Autowired
private StringRedisTemplate stringRedisTemplate;

@Value("${auth.ttl}")
private long ttl;
/**
 * 根据参数获取令牌
 *
 * @param username     用户名
 * @param password     用户密码
 * @param clientId     当前服务的认证id
 * @param clientSecret 当前服务的认证密码
 * @return
 */
@Override
public AuthToken login(String username, String password, String clientId, String clientSecret) {
    // 1.申请令牌
    // 1.2构建请求url
    // 1.2.1通过负载均衡获取相应的服务对象
    ServiceInstance serviceInstance = loadBalancerClient.choose("user-auth");
    // 1.2.2根据服务对象获取请求uri
    URI uri = serviceInstance.getUri();
    // 1.2.3.拼接生成请求的url
    String url = uri + "/oauth/token";

    // 1.3.1 构建请求的请求体,设置认证的方式 记忆用户密码
    MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
    body.add("grant_type", "password");
    body.add("username", username);
    body.add("password", password);
    // 1.3.2 设置请求头
    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.add("Authorization", this.getHttpBasic(clientId, clientSecret));
    // 1.3 构建请求参数封装对象

    HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
    // 1.1 通过restTemplate发送请求
    ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);

    // 2.组装令牌的数据
    // 2.1获取返回的令牌数据
    Map map = responseEntity.getBody();
    // 2.1非空校验,如果获取到的参数为空,则申请令牌失败
    if (map == null || map.get("access_token") == null || map.get("refresh_token") == null || map.get("jti") == null) {
        throw new RuntimeException("申请令牌失败");
    }
    // 2.2将结果数据封装到AuthToken对象中
    AuthToken authToken = new AuthToken();
    authToken.setAccessToken((String) map.get("access_token"));
    authToken.setRefreshToken((String) map.get("refresh_token"));
    authToken.setJti((String)map.get("jti"));
    // 3.网redis中存储令牌
    // 3.1将获取到的数据中jki作为redis的key jwt作为redis的value进行存储
    // 设置#token存储到redis的过期时间
    stringRedisTemplate.boundValueOps(authToken.getJti()).set(authToken.getAccessToken(),ttl, TimeUnit.SECONDS);
    return authToken;
}

private String getHttpBasic(String clientId, String clientSecret) {
    String value = clientId + ":" + clientSecret;
    byte[] encode = Base64Utils.encode(value.getBytes());
    return "Basic " + new String(encode);
}

}

2.4 认证接口表现层
步骤 :
1). 接收参数, 进行健壮性判定 ;
2). 调用service层方法, 申请令牌 ;
3). 需要将短令牌 jti , 存储到Cookie 中 ;

@Controller
@RequestMapping("/oauth")
public class AuthServiceController {

@Autowired
private AuthService authService;

@Value("${auth.clientId}")
private String clientId;

@Value("${auth.clientSecret}")
private String clientSecret;

@Value("${auth.cookieDomain}")
private String cookieDomain;

@Value("${auth.cookieMaxAge}")
private int cookieMaxAge;


@RequestMapping("/login")
@ResponseBody
public Result login(String username, String password, HttpServletResponse response){
    //     1). 接收参数, 进行健壮性判定 ;
    if (StringUtils.isEmpty(username)){
        throw new RuntimeException("请输入用户名");
    }
    if (StringUtils.isEmpty(password)){
        throw new RuntimeException("请输入密码");
    }

    //     2). 调用service层方法, 申请令牌 ;
    AuthToken authToken = authService.login(username, password, clientId, clientSecret);

    //     3). 需要将短令牌 jti , 存储到Cookie 中 ;
    // 当再次访问其他服务的时候就会携带着cookie 键为uid 值为jti 可以通过jti 获取到令牌,
    CookieUtil.addCookie(response,cookieDomain,"/","uid",authToken.getJti(),cookieMaxAge,false);
    return new Result(true, StatusCode.OK,"登录成功",authToken.getJti());
}

}

2.5 动态获取用户信息
由于目前的代码中, 密码是在自定义认证类中写死的 , 我们需要动态获取用户的信息 ;
在这里插入图片描述

1). 定义feign远程调用接口
@FeignClient(name = “user”)
public interface UserFeign {
@GetMapping("/user/load/{username}")
public User findUserInfo(@PathVariable(“username”) String username);
}

2). user 微服务中开发该接口
@GetMapping("/load/{username}")
public User findUserInfo(@PathVariable(“username”) String username){
User user = userService.findById(username);
return user;
}

3). auth 认证微服务中远程调用,获取用户信息

在这里插入图片描述
4). 在user 微服务中ResourceServerConfig类中 , 放行

在这里插入图片描述
3. 认证服务对接网关
3.1 网关搭建
1). pom.xml
可以直接在父工程 gateway中引入即可 ;


org.springframework.cloud
spring-cloud-starter-gateway

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

2). application.yml
spring:
application:
name: gateway-web
cloud:
gateway:
globalcors:
cors-configurations:
'[/]’: # 匹配所有请求
allowedOrigins: “*” #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
- id: changgou_goods_route
uri: lb://goods
predicates:
- Path=/api/album/
,/api/brand/,/api/cache/,/api/categoryBrand/,/api/category/,/api/para/,/api/pref/,/api/sku/,/api/spec/,/api/spu/,/api/stockBack/,/api/template/**
filters:
#- PrefixPath=/brand
- StripPrefix=1

      #用户微服务
    - id: changgou_user_route
      uri: lb://user
      predicates:
        - Path=/api/user/**,/api/address/**,/api/areas/**,/api/cities/**,/api/provinces/**
      filters:
        - StripPrefix=1

      #认证微服务
    - id: changgou_oauth_user
      uri: lb://user-auth
      predicates:
        - Path=/api/oauth/**
      filters:
        - StripPrefix=1

redis:
host: 192.168.200.128
server:
port: 8001
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:6868/eureka
instance:
prefer-ip-address: true
management:
endpoint:
gateway:
enabled: true
web:
exposure:
include: true

3). 引导类
@SpringBootApplication
@EnableEurekaClient
public class WebGatewayApplication {

public static void main(String[] args) {
    SpringApplication.run(WebGatewayApplication.class,args);
}

}

3.2 网关过滤器
逻辑 :
1). 判定请求是否是登录请求, 如果是, 则放行 ;
2). 判定Cookie中有没有jti短令牌, 如果没有 , 则拒绝访问 ;
3). 判定Redis中有没有jwt令牌, 如果没有, 则拒绝访问 ;
4). 对请求进行增强 , 增加一个头信息 Authorization ------> Bearer xxxxxxxxxxxxx

代码实现 :
@Component
public class AuthFilter implements GlobalFilter, Ordered {

@Autowired
private AuthService authService;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpRequest request = exchange.getRequest();
    ServerHttpResponse response = exchange.getResponse();

    //1.判断当前请求路径是否为登录请求,如果是,则直接放行
    String path = request.getURI().getPath();
    if ("/api/oauth/login".equals(path) ){
        //直接放行
        return chain.filter(exchange);
    }


    //2.从cookie中获取jti的值,如果该值不存在,拒绝本次访问
    String jti = authService.getJtiFromCookie(request);
    if (StringUtils.isEmpty(jti)){
        //拒绝访问
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return response.setComplete();
    }

    //3.从redis中获取jwt的值,如果该值不存在,拒绝本次访问
    String jwt = authService.getJwtFromRedis(jti);
    if (StringUtils.isEmpty(jwt)){
        //拒绝访问
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return response.setComplete();
    }

    //4.对当前的请求对象进行增强,让它会携带令牌的信息
    request.mutate().header("Authorization","Bearer "+jwt);
    return chain.filter(exchange);
}

@Override
public int getOrder() {
    return 0;
}

}

测试:
A. 登录, 获取到令牌(Redis , Cookie)
B. 调用用户微服务的接口, 查询用户信息

  1. 自定义登录页面
    1.1 定义登录页面
    1). pom.xml

    org.springframework.boot
    spring-boot-starter-thymeleaf

2). 引入静态资源及模板文件

3). 定义Controller
@RequestMapping("/toLogin")
public String toLogin(){
return “login”;
}

4). 配置白名单(不登录也能够访问的资源)
在WebSecurityConfig中配置 :
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/oauth/login",
“/oauth/logout”,"/oauth/toLogin","/login.html","/css/","/data/","/fonts/","/img/","/js/**");
}

5). 开启表单登录,设置登录页面
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.httpBasic() //启用Http基本身份验证
.and()
.formLogin() //启用表单身份验证
.and()
.authorizeRequests() //限制基于Request请求访问
.anyRequest()
.authenticated(); //其他请求都需要经过验证

//开启表单登录
http.formLogin().loginPage("/oauth/toLogin")//设置访问登录页面的路径
.loginProcessingUrl("/oauth/login");//设置执行登录操作的路径
}

测试 :
需要网关的认证过滤器中, 来放行两个链接 : /oauth/login , /oauth/toLogin
1.2 网关过滤器代码优化
由于在系统中, 有很多的URL都不需要登录就可以访问(登录url , 跳转页面url , 注册用户url , 验证码url), 如果全部在AuthFilter进行if条件判断,维护起来不方便 , 所以定义了一个工具UrlFilter ;
String path = request.getURI().getPath();
if (!UrlFilter.hasAuthorize(path) ){
//直接放行
return chain.filter(exchange);
}

public class URLFilter {
/**
* 所有需要传递令牌的地址
*/
public static String filterPath = “/api/wseckillorder,/api/seckill,/api/wxpay,/api/wxpay/,/api/worder/,/api/user/,/api/address/,/api/wcart/,/api/cart/,/api/categoryReport/,/api/orderConfig/,/api/order/,/api/orderItem/,/api/orderLog/,/api/preferential/,/api/returnCause/,/api/returnOrder/,/api/returnOrderItem/**”;

public static boolean hasAuthorize(String url){
    // 获取到每一个需要传递令牌的url的地址集合
    String[] split = filterPath.replace("**", "").split(",");
    for (String value : split) {
        // 判断如果url以 上述的地址开头,则返回true 需要传递令牌
        if (url.startsWith(value) || value.startsWith(url)){
            return true;
        }
    }
    // url不需要传递令牌
    return false;
}

}

1.3页面

忘记密码?
  1. 权限控制
    2.1 用户授权
    SpringSecurity 是一个安全框架 , 包含两个部分 : 认证 , 授权 ;

在这里插入图片描述
2.2 JWT令牌包含角色权限
注意 : 自定义认证UserDetailsServiceImpl 的返回值 UserDetails 对象, 将会包含到JWT令牌的第二部分内容 ;

在这里插入图片描述
2.3 权限控制
1). 资源服务配置类中开启全局方法授权

在这里插入图片描述
2). 方法权限控制

在这里插入图片描述
在这里插入图片描述
如果在方法中没有加 @PreAuthorize注解 , 则只需要有合法的JWT令牌就可以访问 , 不会判定权限信息;
关于用户的权限信息, 需要配置在数据库中的:

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Oauth2+jwt+redis+cookie+springsecurity+springboot+springcloud(用户登录认证授权) 的相关文章

  • Java new Date() 打印

    刚刚学习 Java 我知道这可能听起来很愚蠢 但我不得不问 System out print new Date 我知道参数中的任何内容都会转换为字符串 最终值是 new Date 返回对 Date 对象的引用 那么它是如何打印这个的呢 Mo
  • 如何默认将 Maven 插件附加到阶段?

    我有一个 Maven 插件应该在编译阶段运行 所以在项目中consumes我的插件 我必须做这样的事情
  • Play框架运行应用程序问题

    每当我尝试运行使用以下命令创建的新 Web 应用程序时 我都会收到以下错误Play http www playframework org Error occurred during initialization of VM Could no
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • 列出jshell中所有活动的方法

    是否有任何命令可以打印当前 jshell 会话中所有新创建的方法 类似的东西 list但仅适用于方法 您正在寻找命令 methods all 它会打印所有方法 包括启动 JShell 时添加的方法 以及失败 被覆盖或删除的方法 对于您声明的
  • 磁模拟

    假设我在 n m 像素的 2D 表面上有 p 个节点 我希望这些节点相互吸引 使得它们相距越远吸引力就越强 但是 如果两个节点之间的距离 比如 d A B 小于某个阈值 比如 k 那么它们就会开始排斥 谁能让我开始编写一些关于如何随时间更新
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • 斯坦福 NLP - 处理文件列表时 OpenIE 内存不足

    我正在尝试使用斯坦福 CoreNLP 中的 OpenIE 工具从多个文件中提取信息 当多个文件 而不是一个 传递到输入时 它会给出内存不足错误 All files have been queued awaiting termination
  • 如何为俚语和表情符号构建正则表达式 (regex)

    我需要构建一个正则表达式来匹配俚语 即 lol lmao imo 等 和表情符号 即 P 等 我按照以下示例进行操作http www coderanch com t 497238 java java Regular Expression D
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • 使用Caliper时如何指定命令行?

    我发现 Google 的微型基准测试项目 Caliper 非常有趣 但文档仍然 除了一些示例 完全不存在 我有两种不同的情况 需要影响 JVM Caliper 启动的命令行 我需要设置一些固定 最好在几个固定值之间交替 D 参数 我需要指定
  • AWS 无法从 START_OBJECT 中反序列化 java.lang.String 实例

    我创建了一个 Lambda 函数 我想在 API 网关的帮助下通过 URL 访问它 我已经把一切都设置好了 我还创建了一个application jsonAPI Gateway 中的正文映射模板如下所示 input input params
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 仅将 char[] 的一部分复制到 String 中

    我有一个数组 char ch 我的问题如下 如何将 ch 2 到 ch 7 的值合并到字符串中 我想在不循环 char 数组的情况下实现这一点 有什么建议么 感谢您花时间回答我的问题 Use new String value offset
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s

随机推荐

  • ElementUI table表格列动态渲染

    文章目录 一 概述 二 实现 一 概述 一般写table时 列都是固定 现有业务需求 列是不固定的 根据api返回的数据 进行动态渲染 官方table示例 链接如下 https element eleme cn zh CN componen
  • mysql服务重启和关闭

    没有加环境变量 重启MySQL 服务的步骤 1 win R 打开 cmd 确定 2 切换到MySQL的bin目录
  • LeetCode--初级算法--实现strStr()

    实现strStr 实现 strStr 函数 给定一个 haystack 字符串和一个 needle 字符串 在 haystack 字符串中找出 needle 字符串出现的第一个位置 从0开始 如果不存在 则返回 1 示例 1 输入 hays
  • C++ std::vector指定位置插入

    使用vector 必须加上 include
  • postgresql tuple介绍

    文章目录 前言 tuple结构 tupleheader介绍 tuple组装 结尾 前言 本文是基于postgresql 14的代码进行分析解读 演示是在centos8系统上进行 1 tuple结构 HeapTupleHeaderData n
  • Sublime Text 3中文乱码问题

    Sublime Text 3 默认编码格式为UTF 8 GBK会乱码 一 安装Package Control 1 下载Package Control sublime package 2 把下载的Package Control sublime
  • Spring事件监听机制使用和原理解析

    前言 好久没有更新Spring了 今天来分享一下Spring的事件监听机制 之前分享过一篇Spring监听机制的使用 今天从原理上进行解析 Spring的监听机制基于观察者模式 就是就是我们所说的发布订阅模式 这种模式可以在一定程度上实现代
  • Visual Studio 下的常见C++迭代器:for(:) ;for each( in );foreach(,)

    以下内容是摘抄博客 Visual Studio 下的常见C 迭代器 for for each in foreach ClayQ的博客 CSDN博客 std list
  • idea键盘录入3个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出

    分析 1 创建学生类 姓名 语文成绩 数学成绩 英语成绩 总分 2 创建TreeSet集合 用来存储学生对象 3 录入学生信息 4 创建学生对象的比较器 5 把学生对象添加到TreeSet集合中 6 遍历集合 Student 学生类 pac
  • 【论文笔记】BLIP-2: Bootstrapping Language-Image Pretrainingwith Frozen Image Encoders and Large Language

    1 介绍 BLIP 2通过轻量级的查询转换器弥补了模态缺口 该转换器分两个阶段进行预训练 第一阶段从冻结图像编码器中引导视觉语言表示学习 第二阶段从冻结的语言模型中引导视觉到语言生成性学习 1 1 动机 是想要在现成的语言和视觉的单模态模型
  • double使用BigDecimal进行计算出现精确度问题

    1 为什么要用BigDecimal去计算数据 原因在于我们的计算机是二进制的 浮点数 double float 没有办法是用二进制进行精确表示 我们的CPU表示浮点数由两个部分组成 指数和尾数 这样的表示方法一般都会失去一定的精确度 有些浮
  • 谈谈互联网创业未来的发展方向我们如何把握

    版权声明 更多赚钱项目关注大众创业网 https cye yunshangxitong cn 马云如今 除了公务员和职业组织的 铁饭碗 似乎只有创业才是出路 许多人选择自己创业 但对于一个人来说 有哪些创业项目呢 马云秘密分享以下小笔无利可
  • 完全数的性质

    完全数性质 1 古希腊数学家欧几里得是通过 2 n 1 2 n 1 的表达式发现头四个完全数的 2 偶完全数都是以6或8结尾 如果以8结尾 那么就肯定是以28结尾 3 除6以外的偶完全数 把它的各位数字相加 直到变成个位数 那么这个个位数一
  • Learun FrameWork 强大工作流引擎,让OA更智能

    互联网的发展促使企业在信息化的道路上不断探索 而随着企业信息化进程的不断深入 OA协同办公的概念也逐步进入大众的视野 OA的选型关乎企业的生存发展 除了需要重视 OA技术 OA品牌 OA产品 OA服务 四大要素之外 更重要的其实是让OA变得
  • 如何使用VS2015编译运行DX11版本龙书配套源码

    这篇文章是翻译http www d3dcoder net 网站上Frank Luna 龙书作者本人 的解决方案 近来 我收到求助emails emalis询问如何解决本书附带的代码使用Visula Studio 2015编译失败的问题 这篇
  • 二、机器学习模型评估

    二 机器学习模型评估 2 1 模型评估 基本概念 错误率 Error Rate 预测错误的样本数a占样本总数的比例m E a m E frac a m E ma
  • C语言-字符串-指针-排序

    概述 使用C语言 实现字符串排序算法 冒泡排序 编码环境 Visual Studio 2022 1 code char str0 C char str1 JAVA char str2 C char str3 PHP char str4 HT
  • 【C/C++类库】:uuid 通用唯一识别码

    SourceForge libuuid下载 CSDN libuuid下载安装 1 libuuid 下载安装 tar xzvf libuuid 1 0 3 tar gz cd libuuid 1 0 3 configure make sudo
  • JVM--基础--26.5--工具--jhat

    JVM 基础 26 5 工具 jhat 1 介绍 分析jmap生成的dump jhat内置了一个微型的HTTP HTML服务器 生成dump的分析结果后 可以在浏览器中查看 注意 一般不会直接在服务器上进行分析 因为jhat是一个耗时并且耗
  • Oauth2+jwt+redis+cookie+springsecurity+springboot+springcloud(用户登录认证授权)

    用户认证分析 1 单点登录 一处登录 处处运行 SSO gt Single Sign On 作用 A 解决集群环境下的登录问题 B 解决多套互信的系统之间的登录问题 gt 天猫 淘宝 天猫超市 天猫国际 2 第三方登录 QQ登录 微博登录