10_单点登录SSO

10_单点登录SSO是什么在企业发展初期,企业使用的系统很少,通常一个或者两个,每个系统都有自己的登录模块,运营人员每天用自己的账号登录,很方便。但随着企业的发展,用到的系统随之增多,运营人员在操作不同的系统时,需要多次登录,而且每个系统的账号都不一样,这对于运营人员来说,很不方便。于是,就想到是不是可以在一个系统登录,其他系统就不用登录了呢?这就是单点登录要解决的问题。单点登录英文全称SingleSignOn,简称就是SSO。它的解释是:在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统Coo

大家好,又见面了,我是你们的朋友全栈君。

是什么

在企业发展初期,企业使用的系统很少,通常一个或者两个,每个系统都有自己的登录模块,运营人员每天用自己 的账号登录,很方便。但随着企业的发展,用到的系统随之增多,运营人员在操作不同的系统时,需要多次登录, 而且每个系统的账号都不一样,这对于运营人员来说,很不方便。于是,就想到是不是可以在一个系统登录,其他系统就不用登录了呢?这就是单点登录要解决的问题。

单点登录英文全称Single Sign On,简称就是SSO。它的解释是:在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统


Cookie-Session登录

在这里插入图片描述

我们在浏览器(Browser)中访问一个应用,这个应用需要登录,我们填写完用户名和密码后,完成 登录认证。这时,我们在这个用户的session中标记登录状态为yes(已登录),同时在浏览器(Browser)中写入Cookie,这个Cookie是这个用户的唯一标识。下次我们再访问这个应用的时候,请求中会带上这个Cookie,服务端会根据这个Cookie找到对应的session,通过session来判断这个用户是否登录。如果不做特殊配置,这个 Cookie的名字叫做jsessionid,值在服务端(server)是唯一的


Cookie-Session解决单点登录

场景: 有个域名叫做:a.com,同时有两个业务系统分别为:app1.a.com和 app2.a.com。我们要做单点登录(SSO),需要一个登录系统,叫做: sso.a.com,需要实现只要在sso.a.com登录,app1.a.com和app2.a.com就也登录了

解决问题1: Cookie不能跨域问题

sso登录以后,可以将Cookie的域设置为顶域,即.a.com,这样所有子域的系统都可以访问到顶域的Cookie。我们在设置Cookie时,只能设置顶域和自己的域,不能设置其他的域。比如:我们不能在自己的系统中给baidu.com的域设置Cookie

解决问题2: Session不能共享问题

我们在sso系统登录了,这时再访问app1,Cookie也带到了 app1的服务端(Server),app1的服务端怎么找到这个Cookie对应的Session呢?这里就要把3个系统的Session共享,如图所示。共享Session的解决方案有很多,例如:SpringSession。

在这里插入图片描述

基于token的认证登录

当我们谈到利用token进行认证,我们一般说的就是利用JSON Web Tokens(JWTs)进行认证

基于token的身份验证是无状态的,服务器不需要记录哪些用户已经登录或者哪些JWTs已经处理。每个发送到服务器的请求都会带上一个token,服务器利用这个token检查确认请求的真实性

如果说Cookie-Session登录方式可以看成是去银行办理的银行卡,你的银行卡信息都记录在银行

那么可以把token理解成一张演唱会的门票。服务器(演唱会主办方)每次只需要检查你这张门票的有效性,不需要知 道你这张门票是在哪里买的,从谁买的,什么时候买的等等。不同等级的门票可以坐的位置不同,同样的,权限不同的用户可以进行的操作也不同。

在这里插入图片描述


是什么

JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方式,可以在各方之间作为JSON对象安全地传输信息。此信息可以通过数字签名进行验证和信任

通俗来讲,JWT是一个含签名并携带用户相关信息的加密串,页面请求校验登录接口时,请求头中携带JWT串到后端服务,后端通过签名加密串匹配校验,保证信息未被篡改。校验通过则认为是可靠的请求,将正常返回数据


应用场景

授权。

这是最常见的使用场景,解决单点登录问题。因为JWT使用起来轻便,开销小,服务端不用记录用户状态信息(无状态),所以使用比较广泛


优缺点

优点:

  1. 因为token存储在客户端,服务器只负责解码。这样不需要占用服务器端资源。

  2. 服务器端可以无限扩展,负载均衡器可以将用户传递到任何服务器,服务器都能知道用户信息,因为jwt里面包含了。

  3. 数据安全,因为有签名,防止了篡改,但信息还是透明的,不要放敏感信息。

  4. 放入请求头提交,很好的防止了csrf攻击

缺点:

  1. 安全性。由于jwt的payload是使用base64编码的,并没有加密,因此jwt中不能存储敏感数据。而session1的信息是存在服务端的,相对来说更安全
  2. 性能 jwt太长。由于是无状态使用JWT,所有的数据都被放到JWT里,如果还要进行一些数据交换,那载荷会更大,经过编码之后导致jwt非常长,cookie的限制大小一般是4k,cookie很可能放不下,所以jwt一般放在 local storage 里面。并且用户在系统中的每一次http请求都会把jwt携带在Header里面,http请求的Header 可能比Body还要大。而sessionId只是很短的一个字符串,因此使用jwt的http请求比使用session的开销大得多。
  3. 一次性无状态。无法废弃。通过上面jwt的验证机制可以看出来,一旦签发一个jwt,在到期之前就会始终有效,无法中途废弃。例如你在payload中存储了一些信息,当信息需要更新时,则重新签发一个jwt,但是由于旧的jwt还没过期,拿着这个旧的jwt依旧可以登录,那登录后服务端从jwt中拿到的信息就是过时的。

使用方法

结构

正常的JWT数据结构应该如下

img

它是一个很长的字符串,中间用点(.)分隔成三个部分

JWT的三个部分依次: Header – 头部 、Payload – 负载 、Signature(签名)

即:Header.Payload.Signature

对token进行Base64解码:


Header
{ 
   
	alg: "HS256", # alg属性表示签名的算法,默认算法为HS256
	typ: "JWT" # typ属性表示这个令牌的类型,JWT令牌 就为JWT
 }

这个是JWT第一段数据,表示头部信息,主要的作用是描述JWT的元数据

Payload

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

iss (issuer):签发人

exp (expiration time):过期时间

sub (subject):主题

aud (audience):受众

nbf (Not Before):生效时间

iat (Issued At):签发时间

jti (JWT ID):编号

除了官方字段,你还可以在这个部分定义私有字段

{

“sub”: “1234567890”,
“name”: “John Doe”,
“age”: “19”
}

注意:JWT默认是明文展示,任何人都可以读取到,所以此处不要放私密信息

这个 JSON 对象也要使用 Base64URL 算法转成字符串。


Signature

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

  HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用”点”(.)分隔,就可以返回给用户。


单点登录微服务

单点登录微服务父项目:supergo_sso

1、建Module:supergo_sso

2、改pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>supergo_parent1</artifactId>
        <groupId>com.supergo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>supergo_sso</artifactId>

    <!--父项目-->
    <packaging>pom</packaging>
</project>

单点登录微服务提供者:supergo_sso_service

1、建Module:supergo_sso_service

2、改pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>supergo_sso</artifactId>
<groupId>com.supergo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>supergo_sso_service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.supergo</groupId>
<artifactId>supergo-base-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--jwt 依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!--加密依赖-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
</dependencies>
</project>

3、启动类

package com.supergo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@EnableEurekaClient
@MapperScan("com.supergo.mapper")
public class SsoApplication9005 { 

public static void main(String[] args) { 

SpringApplication.run(SsoApplication9005.class, args);
}
}

4、建yml

# 端口
server:
port: 9005
# 名字
spring:
application:
name: supergo-manager # 代表的就是我以什么样的名字入驻进的注册中心
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: com.mysql.jdbc.Driver # mysql驱动类
url: jdbc:mysql://127.0.0.1:3306/supergo?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: 123456
mybatis:
type-aliases-package: com.supergo.pojo #所有别名类所在的包
eureka:
client:
register-with-eureka: true # 表示将自己注册到 eureka server ,默认为 true
fetch-registry: true # 表示是否从eureka server 抓取已有的注册信息,默认为true。单节点为所谓,集群必须为 true,才能配合ribbon使用负载均衡
service-url:
# 单机版:只用注册进一个服务中心【defaultZone: http://127.0.0.1:7001/eureka/】
defaultZone: http://eureka7001.com:7001/eureka/
# 集群版:需要同时注册进每个注册中心
# defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com/eureka/
# 显示的服务主机名称
instance:
prefer-ip-address: true # 访问路径显示 ip【统一:方便调试】
ip-address: 127.0.0.1
instance-id: ${ 
eureka.instance.ip-address}.${ 
server.port}
lease-renewal-interval-in-seconds: 3
lease-expiration-duration-in-seconds: 10
#actuator服务监控与管理
management:
endpoint:
#开启端点
shutdown:
enabled: true
health:
show-details: always
# 加载所有的端点
endpoints:
web:
exposure:
include: "*"
# 配置生成token所需参数[自定义]
jwt:
config:
key: abc123 # 生成token的密钥
ttl: 30 # 过期时间

5、JWT测试

token创建
@Test
public void createJwt() { 

//生成token
String token = Jwts.builder()
.setId("123")
.setSubject("admin") //主题
.setIssuedAt(new Date()) //签发时间
.signWith(SignatureAlgorithm.HS256, "abc12")//签名
.compact();
System.out.println(token);
}

在这里插入图片描述


token解析

jwt在线工具对token解析: https://jwt.io/

将生成的token进行解析:

在这里插入图片描述


代码实现:

@Test
public void parseJwt() { 

String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjMiLCJzdWIiOiJhZG1pbiIsImlhdCI6MTYxMDU5MjkxNX0.jzn50cbf9DhuodVey6pty0WKl3Uvl0x_d7ChRvXOkaA";
//解析token
Jws<Claims> jws = Jwts.parser().setSigningKey("abc123").parseClaimsJws(token);
Claims claims = jws.getBody(); //获取payload部分
System.out.println(claims);
}

在这里插入图片描述


token过期校验

token过期后,便不可以再使用

@Test
public void expireJwt() { 

//过期时间:当前时间+10s
long exp = System.currentTimeMillis() + 10 * 1000;
//生成token
String token = Jwts.builder()
.setId("1234")
.setSubject("admin")
.setIssuedAt(new Date()) //当前时间
.setExpiration(new Date(exp)) // 过期时间
.signWith(SignatureAlgorithm.HS256, "a123")//签名
.compact();
//读取token
Jws<Claims> jws = Jwts.parser().setSigningKey("a123").parseClaimsJws(token);
Claims claims = jws.getBody();
System.out.println(claims);
//等待10s
for (int i = 10; i > 0; i--) { 

System.out.println("倒计时 " + i);
try { 

Thread.sleep(1000);
} catch (InterruptedException e) { 

e.printStackTrace();
}
}
//再次读取token[参数1:签名,参数2:token]
jws = Jwts.parser().setSigningKey("a123").parseClaimsJws(token);
claims = jws.getBody();
System.out.println(claims);
}

在这里插入图片描述


自定义claims
@Test
public void claimsJwt() { 

//过期时间当前时间+10s
long exp = System.currentTimeMillis() + 10 * 1000;
//生成token
String token = Jwts.builder()
.setId("1234")
.setSubject("admin")
.setIssuedAt(new Date()) //当前时间
.setExpiration(new Date(exp)) // 过期时间
.claim("key1", "123")  //自定义claims
.claim("key2", "abc")
.signWith(SignatureAlgorithm.HS256, "a123")//签名
.compact();
//读取token
Jws<Claims> jws = Jwts.parser().setSigningKey("a123").parseClaimsJws(token);
Claims claims = jws.getBody();
System.out.println(claims);
}

在这里插入图片描述


密码加密

任何应用考虑到安全,绝不能明文的方式保存密码。密码应该通过哈希算法进行加密。 有很多标准的算法比如SHA 或者MD5,结合salt(盐)是一个不错的选择。 Spring Security 提供了BCrypt强哈希算法,可以用来加密密码

添加依赖 :

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>

测试:

@Test
public void testBCrypt() { 

//使用BCrypt强哈希算法并加盐:效果与MD5+加盐相同
String password = BCrypt.hashpw("123", BCrypt.gensalt());
System.out.println(password);
//检查密码
//参数1:明文密码,参数2:加密之后的结果
//这样即使每次加密后的结果不同[即使相同的密码存到数据库的数据也可能不一样],只要判断是否与明文密码相同即可
boolean result = BCrypt.checkpw("123", "$2a$10$yxogUGLdYMx8BGxMWHri0.XYu8dnX.iyR5xS8ABrTOg3xhL4Ae4xu");
System.out.println(result);
}

在这里插入图片描述


6、SSO实现

JWT认证流程:

  1. 用户提供用户名和密码登录
  2. 服务器校验用户是否正确,如正确,就返回token给客户端,此token可以包含用户信息
  3. 客户端存储token,可以保存在cookie或者local storage
  4. 客户端以后请求时,都要带上这个token,一般放在请求头中
  5. 服务器判断是否存在token,并且解码后就可以知道是哪个用户
  6. 服务器这样就可以返回该用户的相关信息了

JWT工作方式:

在用户进行认证登录时,登录成功后服务器会返回一个JWT给客户端;那这个JWT就是用户的凭证,以后到哪里去都要带上这个凭证token。尤其访问受保护的资源的时候,通常把JWT放在Authorization header中。要用 Bearer schema,如header请求头中:

Authorization: Bearer <token>

Bearer与 之间加空格

在这里插入图片描述


7、登录处理

改yml
# 配置生成token所需参数
jwt:
config:
key: abc123 # 生成token的密钥
ttl: 30 # 过期时间
JWT工具类

提供生成token与解析token

package com.supergo.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
/** * @Author: xj0927 * @Description: * @Date Created in 2021-01-13 19:25 * @Modified By: */
@ConfigurationProperties(prefix = "jwt.config") //从配置文件读取密钥与过期时间
@Component
public class JwtUtil { 

private String key; //密钥
private long ttl;//过期时间
//生成token
public String createToken(String id, String subject, String role) { 

JwtBuilder builder = Jwts.builder()
.setId(id)
.setSubject(subject)//主题
.setIssuedAt(new Date())//现在时间
.signWith(SignatureAlgorithm.HS256, key);//密钥
if (ttl > 0) { 

builder.setExpiration(new Date(System.currentTimeMillis() + ttl * 1000));//过期时间
}
return builder.compact();
}
//解析token
public Claims parseToken(String token) { 

return Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
}
public String getKey() { 

return key;
}
public void setKey(String key) { 

this.key = key;
}
public long getTtl() { 

return ttl;
}
public void setTtl(long ttl) { 

this.ttl = ttl;
}
}
pojo
package com.supergo.pojo;
/** * @Author: xj0927 * @Description: 接收用户输入的账户密码 * @Date Created in 2021-01-13 19:43 * @Modified By: */
public class UserInfo { 

private String username;
private String password;
public UserInfo(String username, String password) { 

this.username = username;
this.password = password;
}
public UserInfo() { 

}
public String getUsername() { 

return username;
}
public void setUsername(String username) { 

this.username = username;
}
public String getPassword() { 

return password;
}
public void setPassword(String password) { 

this.password = password;
}
}

Service

接口:

public interface UserService extends BaseService<User> { 

//登陆方法
public HttpResult doLogin(UserInfo userInfo);
}

实现类:

@Service
public class UserImpl extends BaseServiceImpl<User> implements UserService { 

@Autowired
private UserService userService;
@Autowired
private JwtUtil jwtUtil;
@Override
public HttpResult doLogin(UserInfo userInfo) { 

//根据用户名查用户是否存在
User user = new User();
user.setUserName(userInfo.getUsername());
List<User> list = userService.findByWhere(user);
if (list == null || list.size() == 0) { 

return HttpResult.error(401, "用户名不存在");
}
//如果有结果,判断密码是否正确[此密码是经过BCrypt加密了的]
User user1 = list.get(0);
if (!BCrypt.checkpw(userInfo.getPassword(), user1.getPassword())) { 

return HttpResult.error(401, "密码不正确");
}
//密码正确:生成token
//返回token
String token = jwtUtil.createToken(user.getId() + "", user.getName(), "admin");
return HttpResult.ok(token);
}
}

Controller
@RestController
@RequestMapping("/user")
public class UserController { 

@Autowired
private UserService userService;
@PostMapping("/doLogin")
public HttpResult doLogin(@RequestBody UserInfo userInfo) { 

System.out.println(userInfo.getUsername());
return userService.doLogin(userInfo);
}
}

测试

输入:

POST http://localhost:9005/user/doLogin

在这里插入图片描述


8、身份校验

身份校验应该在不同的微服务中来进行身份校验。我们在supergo_manager_service中品牌微服务中进行身份校验

JWT传递的方法是在头信息中添加Authorization ,内容为Bearer+空格 +token

Authorization: Bearer <token>
改pom
<!--token依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
配置JwtUtil组件
package com.supergo.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
/** * @Author: xj0927 * @Description: * @Date Created in 2021-01-13 19:25 * @Modified By: */
@ConfigurationProperties(prefix = "jwt.config") //从配置文件读取密钥与过期时间
@Component
public class JwtUtil { 

private String key; //密钥
private long ttl;//过期时间
//生成token
public String createToken(String id, String subject, String role) { 

JwtBuilder builder = Jwts.builder()
.setId(id)
.setSubject(subject)//主题
.setIssuedAt(new Date())//现在时间
.signWith(SignatureAlgorithm.HS256, key);//密钥
if (ttl > 0) { 

builder.setExpiration(new Date(System.currentTimeMillis() + ttl * 1000));//过期时间
}
return builder.compact();
}
//解析token
public Claims parseToken(String token) { 

return Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
}
public String getKey() { 

return key;
}
public void setKey(String key) { 

this.key = key;
}
public long getTtl() { 

return ttl;
}
public void setTtl(long ttl) { 

this.ttl = ttl;
}
}

拦截器

在拦截器中进行身份认证

package com.supergo.manager.interceptor;
import com.supergo.manager.exception.AuthException;
import com.supergo.manager.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** * @Author: xj0927 * @Description: 配置拦截器进行身份验证 * @Date Created in 2021-01-13 21:26 * @Modified By: */
@Component
public class AuthInterceptor implements HandlerInterceptor { 

@Autowired
private JwtUtil jwtUtil; //注入对象
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 

System.out.println("拦截器执行====>");
String authHeader = request.getHeader("Authorization");
if (authHeader == null) { 

throw new AuthException("权限不足");
}
if (!authHeader.startsWith("Bearer")) { 

throw new AuthException("权限不足");
}
//得到请求的token
final String token = authHeader.substring(7);
//解析token
Claims claims = jwtUtil.parseToken(token);
if (claims != null) { 

//TODO 权限相关操作
// if ("admin".equals(claims.get("roles"))) {//如果是管理员
// request.setAttribute("admin_claims", claims);
// }
// if ("user".equals(claims.get("roles"))) {//如果是用户
// request.setAttribute("user_claims", claims);
// }
}
//放行
return true;
}
}

配置拦截器
package com.supergo.manager.config;
import com.supergo.manager.interceptor.AuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/** * @Author: xj0927 * @Description: 配置拦截器 * @Date Created in 2021-01-13 21:35 * @Modified By: */
@Configuration
public class AuthConfig implements WebMvcConfigurer { 

@Autowired
private AuthInterceptor authInterceptor;//拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) { 

registry.addInterceptor(authInterceptor).addPathPatterns("/**");//拦截的请求
}
}

全局异常处理

自定义异常:

package com.supergo.manager.exception;
/** * @Author: xj0927 * @Description: 权限认证异常 * @Date Created in 2021-01-13 21:29 * @Modified By: */
public class AuthException extends Exception { 

public AuthException() { 

}
public AuthException(String message) { 

super(message);
}
}

异常处理:

package com.supergo.manager.exception;
import com.supergo.http.HttpResult;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/** * @Author: xj0927 * @Description: * @Date Created in 2021-01-13 21:37 * @Modified By: */
@ControllerAdvice  //全局异常
public class GlobalExceptionResolver { 

//token认证异常
@ExceptionHandler(AuthException.class)
@ResponseBody
public HttpResult authExceptionResolver(AuthException e) { 

return HttpResult.error(401, e.getMessage());
}
//token过期异常
@ExceptionHandler(ExpiredJwtException.class)
@ResponseBody
public HttpResult ExpiredJwtExceptionResolver(ExpiredJwtException e) { 

return HttpResult.error(401, "token已经过期");
}
//系统异常
@ExceptionHandler(Exception.class)
@ResponseBody
public HttpResult exceptionResolver(Exception e) { 

return HttpResult.error(401, e.getMessage());
}
}

测试

正常请求:

在这里插入图片描述


不携带token:

在这里插入图片描述


token过期:

在这里插入图片描述


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/152823.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • linux smartctl 命令,使用smartctl命令检查磁盘

    linux smartctl 命令,使用smartctl命令检查磁盘使用smartctl命令检查磁盘在TS过程中会碰到很多磁盘异常出现影响系统数据或者生产数据的情况,但是有时候无法判断磁盘出现问题是由于磁盘物理损坏还是磁盘SATA口接触不良导致,这个时候smartctl命令就可以很容易判断出磁盘是否存在物理损坏问题,并且及时作出预警。使用smartctl进行SMART测试所有现代硬盘都可通过SMART属性监视其当前状态。这些值提供有关硬盘各种参数的信息,并可提供有…

  • 前端基础知识1

    前端基础知识1’usestrict’varname=’Jay’varperson={name:’Wang’,pro:{name:’Michael’,getName:function(){returnthis.name;}}}console.log(person.pro.getName());varpepole=person.pro.getName;console

  • JVM调优工具

    JVM调优工具JVM调优工具Jconsole:jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用。对垃圾回收算法有很详细的跟踪。JProfiler:商业软件,需要付费。功能强大。VisualVM:JDK自带,功能强大,与JProfiler类似。推荐。如何调优观察内存释放情况、集合类检查、对象树上面这些调优工具都提供了强大的功能,但是总的来说一般分为以下几类功能堆信息查…

  • Android 获取开发版SHA1和发布版SHA1详细介绍「建议收藏」

    Android 获取开发版SHA1和发布版SHA1详细介绍「建议收藏」前言:项目需求接入百度定位,在创建应用时申请AK,需要用到SHA1,在这里把踩过的坑总结下来,并希望可以适当减少开发小伙伴们的头痛。说来就来上干货一、获取开发版SHA1:1、可以使用AndroidStudio提供的命令控制台,毕竟做Android开发几乎都是用AndroidStudio了。也可以使用黑窗口windows+R并键入cmd即可使用2、接着输入命令cdU…

  • java class加载机制及对象生成机制

    java class加载机制及对象生成机制

  • 查看端口被进程占用命令_cmd查看端口占用

    查看端口被进程占用命令_cmd查看端口占用步骤一:linux使用netstat或者ifconfig命令时,显示命令未找到。通过yumsearchnetstat这个命令,匹配结果如下:=================================匹配:netstat===================bwm-ng.x86_64:BandwidthMonitorNGdstat.noarch:Versatileresourcestatisticstoolnet-snmp.x86_64:Acollecti

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号