使用步骤如下:
1. 添加Gradle依赖:

dependencies {
implementation 'com.auth0:java-jwt:3.3.0'
implementation('org.springframework.boot:spring-boot-starter-aop')
}
2. 登录检验时,使用JWT生成Token令牌(我这里登录用户名是email)。

/**
* 登录检验方法。
* @param user
* @return
*/
public String login(User user) {
// 登录检验逻辑 TODO

//登录检验成功,生成token令牌
String token = tokenService.generateToken(userRepository.findUserByMail(user.getMail()));

//自定义返回值
return null;
}
一、生成和校验Token。
1)生成和校验token令牌的服务类。

/**
* 使用JWT作为Token实现。
*
* @author LEEMER
* Create Date: 2019-05-20
*/
@Service
public class TokenService {
private static final Logger LOGGER = LoggerFactory.getLogger(TokenService.class);

private TokenConfigBean tokenConfigBean;

/**
* Token加密算法。
*/
private Algorithm algorithm;

/**
* Token认证对象。
*/
private JWTVerifier verifier;

private UserRepository userRepository;

public TokenService(TokenConfigBean tokenConfigBean,
Algorithm algorithm,
JWTVerifier verifier,
UserRepository userRepository) {
this.tokenConfigBean = tokenConfigBean;
this.algorithm = algorithm;
this.verifier = verifier;
this.userRepository = userRepository;
}

public String generateToken(User user) {
JWTCreator.Builder builder = JWT.create().withClaim("mail", user.getMail());

builder.withClaim("expiredTime", System.currentTimeMillis()
+ tokenConfigBean.getExpiredTime() * 60 * 1000);

return builder.sign(algorithm);
}

public boolean isValid(String token) {
DecodedJWT jwt;
try {
jwt = verifier.verify(token);
} catch (JWTVerificationException exception){
LOGGER.debug("该Token解码失败:" + token);
return false;
}
long expiredTime = jwt.getClaim("expiredTime").asLong();
if (expiredTime < System.currentTimeMillis()) {
LOGGER.debug("该Token已过期:" + expiredTime);
return false;
}
return true;
}

public String resetExpiredTime(String token) {
DecodedJWT jwt;
try {
jwt = verifier.verify(token);
} catch (JWTVerificationException exception){
return "";
}
User user = userRepository.findUserByMail(jwt.getClaim("mail").asString());
return generateToken(user);
}

public String getValueByMail(String token, String key) {
var trueToken = token.startsWith("Bearer ") ? token.substring(7) : token;
DecodedJWT jwt;
try {
jwt = verifier.verify(trueToken);
} catch (JWTVerificationException exception){
LOGGER.debug("目标Token解析失败:" + trueToken);
return null;
}
return jwt.getClaim(key).asString();
}

public String getValueByMail(String token, int mail) {
return getValueByMail(token, String.valueOf(mail));
}

public <T> List<T> getListValueByMail(String token, String mail, Class<T> cls) {
DecodedJWT jwt;
try {
jwt = verifier.verify(token);
} catch (JWTVerificationException exception){
return null;
}
return jwt.getClaim(mail).asList(cls);
}

public <T> List<T> getListValueByMail(String token, int mail, Class<T> cls) {
return getListValueByMail(token, String.valueOf(mail), cls);
}

public User getUser(String token) {
var mail = getValueByMail(token, "mail");
if (StringUtils.isBlank(mail)) {
LOGGER.error("[getUser] 从该Token中无法提取有效邮箱:{}", token);
return null;
}
return userRepository.findUserByMail(mail);
}
}
2)Token配置Bean:设置token过期时间、混淆。

/**
* @author LEEMER
* Create Date: 2019-05-20
*/
@Configuration
public class TokenConfigBean {

/**
* Token过期时间(单位:分钟)。
*/
private int expiredTime = 30;

/**
* 混淆。
*/
private String secret = "c8e3n23ia0wgn458yqwafn934uf";

public int getExpiredTime() {
return expiredTime;
}

public void setExpiredTime(int expiredTime) {
this.expiredTime = expiredTime;
}

public String getSecret() {
return secret;
}

public void setSecret(String secret) {
this.secret = secret;
}
}
3)Token认证对象和加密算法配置类。

/**
* @author LEEMER
* Create Date: 2019-05-20
*/
@Component
public class BeanConfig {

private TokenConfigBean tokenConfigBean;

public BeanConfig(TokenConfigBean tokenConfigBean) {
this.tokenConfigBean = tokenConfigBean;
}

/**
* Token认证对象。
*/
@Autowired
@Bean
public JWTVerifier getJwtVerifier(Algorithm algorithm) {
return JWT.require(algorithm).build();
}

/**
* Token加密算法。
*/
@Bean
public Algorithm getAlgorithm() {
try {
return Algorithm.HMAC256(tokenConfigBean.getSecret());
} catch (UnsupportedEncodingException e) {
LOGGER.error("生成Token加法算法失败!", e);
throw new RuntimeException(e);
}
}

}
4)自定义控制器请求token认证注解。

/**
* 使用在传统控制器的方法上,进行登录判断,如果没有登录则返回登录界面。
*
* @author LEEMER
* Create Date: 2019-05-20
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ControllerAuthCheck {
}
/**
* @author LEEMER
* Create Date: 2019-05-20
*/
@Aspect
@Component
public class ControllerAuthCheckAspect {

private static final Logger LOGGER = LoggerFactory
.getLogger(ControllerAuthCheckAspect.class);

private UrlConfigBean urlConfigBean;

/**
* Token服务。
*/
private TokenService tokenService;

@Autowired
public ControllerAuthCheckAspect(TokenService tokenService,
UrlConfigBean urlConfigBean) {
this.tokenService = tokenService;
this.urlConfigBean = urlConfigBean;
}

/**
* 定义切入点。
*
* 所有包含AuthCheck注解的方法均会被拦截。
*/
@Pointcut("@annotation(cn.blackbox.annotation.ControllerAuthCheck)")
private void checkAuth() {}

/**
* 环绕增强。
*
* 在调用相关系统模块时,进行权限检查,没有相关权限则不进行目标方法的调用。
*
*/
@Around(value = "checkAuth() && @annotation(controllerAuthCheck) && args(token, ..)",
argNames = "joinPoint, controllerAuthCheck, token")
private Object checkAuth(ProceedingJoinPoint joinPoint,
ControllerAuthCheck controllerAuthCheck,
String token) {
if (!token.startsWith("Bearer ")) {
return "redirect:" + urlConfigBean.getLogin();
} else {
token = token.substring(7);
}

if (!tokenService.isValid(token)) {
return "redirect:" + urlConfigBean.getLogin();
}

try {
return joinPoint.proceed();
} catch (Throwable throwable) {
LOGGER.error("控制器权限控制切面调用目标方法失败!", throwable);
throw new RuntimeException(throwable);
}
}
}

二、使用Token实现相关模块登录认证。
使用场景:请求后台数据的时候我们可以通过token值判断用户是否登录。

1)在JS里面我们可以localStorage.getItem("token")获取token值。如下:

function getLoginDetails() {
$.ajax({
url:"/api/v1/stage/land_details",
method:"GET",
dataType:"JSON",
headers:{
token:localStorage.getItem("token")
},
success : function (result) {

}
})
}
2)后台校验token值,通过我们自定义@ControllerAuthCheck注解实现token校验功能。

@RequestMapping("/land_details")
@ControllerAuthCheck // 检验token的注解,必须要获取token参数才能有效校验
public String toLandDetailsView(@RequestParam(value = "token", required = false, defaultValue = "") String token){
return "/land_details";
}
---------------------

Spring Boot 集成 JWT 实现单点登录授权的更多相关文章

  1. spring security集成cas实现单点登录

    spring security集成cas 0.配置本地ssl连接 操作记录如下: =====================1.创建证书文件thekeystore ,并导出为thekeystore.c ...

  2. Spring Boot使用JWT实现系统登录验证

    简介 什么是JWT(Json Web Token) jwt是为了在网络应用环境间传递声明而执行的一种基于json的开放标准.该token被设计紧凑且安全的,特别适用于SSO场景.jwt的声明一般被用来 ...

  3. Spring Security 集成CAS实现单点登录

    参考:http://elim.iteye.com/blog/2270446 众所周知,Cas是对单点登录的一种实现.本文假设读者已经了解了Cas的原理及其使用,这些内容在本文将不会讨论.Cas有Ser ...

  4. springBoot整合spring security+JWT实现单点登录与权限管理--筑基中期

    写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...

  5. Spring Boot 集成 Swagger2 与配置 OAuth2.0 授权

    Spring Boot 集成 Swagger2 很简单,由于接口采用了OAuth2.0 & JWT 协议做了安全验证,使用过程中也遇到了很多小的问题,多次尝试下述配置可以正常使用. Maven ...

  6. Spring Boot 集成Shiro和CAS

    Spring Boot 集成Shiro和CAS 标签: springshirocas 2016-01-17 23:03 35765人阅读 评论(22) 收藏 举报  分类: Spring(42)  版 ...

  7. 【实验一 】Spring Boot 集成 hibernate & JPA

    转眼间,2018年的十二分之一都快过完了,忙于各类事情,博客也都快一个月没更新了.今天我们继续来学习Springboot对象持久化. 首先JPA是Java持久化API,定义了一系列对象持久化的标准,而 ...

  8. Spring Boot集成Shiro实战

    Spring Boot集成Shiro权限验证框架,可参考: https://shiro.apache.org/spring-boot.html 引入依赖 <dependency> < ...

  9. Spring Boot Security JWT 整合实现前后端分离认证示例

    前面两章节我们介绍了 Spring Boot Security 快速入门 和 Spring Boot JWT 快速入门,本章节使用 JWT 和 Spring Boot Security 构件一个前后端 ...

随机推荐

  1. [Vue-rx] Stream an API using RxJS into a Vue.js Template

    You can map remote data directly into your Vue.js templates using RxJS. This lesson uses axios (and ...

  2. ZOJ 3827 Information Entropy(数学题 牡丹江现场赛)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do? problemId=5381 Information Theory is one of t ...

  3. JS执行环境栈及事件循环机制—简洁明了的讲解

    JavaScript解释器在浏览器中是单线程的,这意味着浏览器在同一时间内只执行一个事件,对于其他的事件我们把它们排队在一个称为 执行栈(调用栈) 的地方.下表是一个单线程栈的抽象视图: 我们已经知道 ...

  4. LeetCode 83. Remove Duplicates from Sorted List (从有序链表中去除重复项)

    Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...

  5. linux命令:find命令

    http://blog.csdn.net/pipisorry/article/details/39831419 linux find命令语法 find [起始文件夹] 寻找条件 操作 find PAT ...

  6. 一些SQL高级函数

    一些SQL高级函数 Posted on 2010-08-08 21:34 moss_tan_jun 阅读(311) 评论(0) 编辑 收藏 长度与分析用 datalength(Char_expr) 返 ...

  7. 68. 对Extjs中store的多种操作

    转自:https://www.cnblogs.com/exmyth/archive/2013/05/16/3082045.html 先来个声明,看着不错,贴过来的,没都测试过. Store.getCo ...

  8. E20170924-hm

    literal   adj. 照字面的; 原义的; 逐字的; 平实的,避免夸张;   n. [印] 错排,文字上的错误; parameter   n. [数] 参数; <物><数&g ...

  9. 湖南集训Day1

    难度 不断网:☆☆☆ 断网:☆☆☆☆ /* 卡特兰数取模 由于数据范围小,直接做. 考试时断网.忘记卡特兰数公式,推错了只有5分. 数学公式要记别每次都现用现搜!!! */ #include<i ...

  10. 如何看待B站疑似源码泄漏的问题?

    今天突然看到关于B站源码泄漏事.网曝B站整个网站后台工程源码遭泄露,开源项目平台Github上疑似出现了Bilibili网站后台工程,内含部分用户名密码.目前官方还没对此事作出任何回应,所以还无法确定 ...