java单点登录token_单点登录(token,JWT)

一.什么事单点登录?

答:单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任。

二.单点登录三种常见方式:

1.session广播机制实现:即session复制

2.使用cookie+redis实现:

(1)在项目中任何一个模块进行登录,登录之后,把用户数据放到两个redis和cookie两个地方:

1>redis:在key :生成唯一随机值(ip,用户id等),value:用户数据

2>把redis里面生成的key值放到cookie里面。

(2)访问项目其他模块,发送请求带着cookie进行发送,获取cookie,拿着cookie值进行做事情:

1>获取到cookie值,到redis中进行查询,根据key值进行查询,如果查到用户数据就是登录。

3.使用token实现

token:按照一定的规则生成字符串,字符串可以包含用户信息(Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码)。

实现方式:

(1)在项目的某个模块进行登录,登录之后,按照一定的规则生成字符串,将用户数据放到字符串中,将字符串进行返回:

1>可以通过cookie进行返回

2>可以通过地址栏进行返回

(2)再访问项目中的其他模块,每次访问都在地址栏带着生成的字符串,在访问模块里面获取地址栏字符串,根据字符串获取用户信息,如果可以获取到,就是登录。

三.JWT是什么?

JWT:Json Web Token,是基于Json的一个公开规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息,他的两大使用场景是:认证和数据交换

使用起来就是,由服务端根据规范生成一个令牌(token),并且发放给客户端。此时客户端请求服务端的时候就可以携带者令牌,以令牌来证明自己的身份信息。

简单来说,JWT就是已经定好了规则,可以使用JWT生成字符串,可以包含用户信息。

四.JWT的规则

eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOjYyNywiZXhwIjoxNTcwMDE0ODg1fQ.vPbQh4syxNCzkKXKPSM93LzzLqoJdzPDNeKz8tz9cFM4NzhIOdPrJcH2DG

-9-9MCUufCgrAhhGjuo85GKV4bOQ

1.JWT的头信息:

{'typ': 'JWT','alg': 'HS256'}

2.有效载荷:主体部分(包含用户信息)

3.签名哈希:防伪标志

五.JWT的使用

1.引入JWT依赖

io.jsonwebtoken

jjwt

2.编写JWT工具类

packagecom.atguigu.commonutils;importio.jsonwebtoken.Claims;importio.jsonwebtoken.Jws;importio.jsonwebtoken.Jwts;importio.jsonwebtoken.SignatureAlgorithm;importorg.springframework.http.server.reactive.ServerHttpRequest;importorg.springframework.util.StringUtils;importjavax.servlet.http.HttpServletRequest;importjava.util.Date;/***@authorhelen

*@since2019/10/16*/

public classJwtUtils {//定义两个常量//token的过期时间

public static final long EXPIRE = 1000 * 60 * 60 * 24;//秘钥

public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";/*生成token字符串的方法*/

public staticString getJwtToken(String id, String nickname){

String JwtToken=Jwts.builder()//设置token的头信息

.setHeaderParam("typ", "JWT")

.setHeaderParam("alg", "HS256")//分类

.setSubject("guli-user")//设置token的过期时间

.setIssuedAt(newDate())

.setExpiration(new Date(System.currentTimeMillis() +EXPIRE))//设置token的主体信息,存储用户信息

.claim("id", id)

.claim("nickname", nickname)//设置签名哈希

.signWith(SignatureAlgorithm.HS256, APP_SECRET)

.compact();returnJwtToken;

}/*** 判断token是否存在与有效

*@paramjwtToken

*@return

*/

public static booleancheckToken(String jwtToken) {if(StringUtils.isEmpty(jwtToken)) return false;try{

Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);

}catch(Exception e) {

e.printStackTrace();return false;

}return true;

}/*** 判断token是否存在与有效

*@paramrequest

*@return

*/

public static booleancheckToken(HttpServletRequest request) {try{

String jwtToken= request.getHeader("token");if(StringUtils.isEmpty(jwtToken)) return false;

Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);

}catch(Exception e) {

e.printStackTrace();return false;

}return true;

}/*** 根据token字符串获取会员id

*@paramrequest

*@return

*/

public staticString getMemberIdByJwtToken(HttpServletRequest request) {

String jwtToken= request.getHeader("token");if(StringUtils.isEmpty(jwtToken)) {return "";

}

Jws claimsJws =Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);

Claims claims=claimsJws.getBody();return (String)claims.get("id");

}

}

六.登录实现

1.编写用户实体类

packagecom.atguigu.educenter.entity;importcom.baomidou.mybatisplus.annotation.FieldFill;importcom.baomidou.mybatisplus.annotation.IdType;importjava.util.Date;importcom.baomidou.mybatisplus.annotation.TableField;importcom.baomidou.mybatisplus.annotation.TableId;importjava.io.Serializable;importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importlombok.EqualsAndHashCode;importlombok.experimental.Accessors;/***

* 会员表

*

*

*@authortestjava

*@since2020-10-28*/@Data

@EqualsAndHashCode(callSuper= false)

@Accessors(chain= true)

@ApiModel(value="UcenterMember对象", description="会员表")public class UcenterMember implementsSerializable {private static final long serialVersionUID = 1L;

@ApiModelProperty(value= "会员id")

@TableId(value= "id", type =IdType.ID_WORKER_STR)privateString id;

@ApiModelProperty(value= "微信openid")privateString openid;

@ApiModelProperty(value= "手机号")privateString mobile;

@ApiModelProperty(value= "密码")privateString password;

@ApiModelProperty(value= "昵称")privateString nickname;

@ApiModelProperty(value= "性别 1 女,2 男")privateInteger sex;

@ApiModelProperty(value= "年龄")privateInteger age;

@ApiModelProperty(value= "用户头像")privateString avatar;

@ApiModelProperty(value= "用户签名")privateString sign;

@ApiModelProperty(value= "是否禁用 1(true)已禁用, 0(false)未禁用")privateBoolean isDisabled;

@ApiModelProperty(value= "逻辑删除 1(true)已删除, 0(false)未删除")privateBoolean isDeleted;

@ApiModelProperty(value= "创建时间")

@TableField(fill=FieldFill.INSERT)privateDate gmtCreate;

@ApiModelProperty(value= "更新时间")

@TableField(fill=FieldFill.INSERT_UPDATE)privateDate gmtModified;

}

2.编写controller层

packagecom.atguigu.educenter.controller;importcom.atguigu.commonutils.R;importcom.atguigu.educenter.entity.UcenterMember;importcom.atguigu.educenter.service.UcenterMemberService;importorg.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;/***

* 会员表 前端控制器

*

*

*@authortestjava

*@since2020-10-28*/@RestController

@RequestMapping("/educenter/member")

@CrossOriginpublic classUcenterMemberController {

@Autowired

UcenterMemberService memberService;//登录

@PostMapping("/login")publicR userLogin(@RequestBody UcenterMember member){//使用service中的方法实现登录//返回token值,使用jwt生成

String token =memberService.login(member);return R.ok().data("token",token);

}//注册

}

3.编写service层

packagecom.atguigu.educenter.service;importcom.atguigu.educenter.entity.UcenterMember;importcom.baomidou.mybatisplus.extension.service.IService;/***

* 会员表 服务类

*

*

*@authortestjava

*@since2020-10-28*/

public interface UcenterMemberService extends IService{//实现登录

String login(UcenterMember member);

}

4.编写serviceImpl

packagecom.atguigu.educenter.service.impl;importcom.atguigu.commonutils.JwtUtils;importcom.atguigu.commonutils.MD5;importcom.atguigu.educenter.entity.UcenterMember;importcom.atguigu.educenter.mapper.UcenterMemberMapper;importcom.atguigu.educenter.service.UcenterMemberService;importcom.atguigu.servicebase.exceptionhandler.GuliException;importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importorg.springframework.stereotype.Service;importorg.springframework.util.StringUtils;/***

* 会员表 服务实现类

*

*

*@authortestjava

*@since2020-10-28*/@Servicepublic class UcenterMemberServiceImpl extends ServiceImpl implementsUcenterMemberService {//实现登录

@OverridepublicString login(UcenterMember member) {//获取手机号和密码

String mobile =member.getMobile();

String password=member.getPassword();//判断手机号和密码是否为空

if(StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)){throw new GuliException(20001,"手机号或者密码为空,登录失败");

}//判断手机号是否正确

QueryWrapper wrapper = new QueryWrapper<>();

wrapper.eq("mobile",mobile);

UcenterMember mobileMember=baseMapper.selectOne(wrapper);//判断查询的对象是否为空

if(mobileMember==null){//没有这个手机号

throw new GuliException(20001,"手机号不存在,登录失败");

}//判断密码是否正确

/**因为数据库中的密码是加密的,

* 所以需要先将传入的密码进行加密,

* 再和数据库的密码进行比较,

* 使用MD5加密*/

if(!MD5.encrypt(password).equals(mobileMember.getPassword())){throw new GuliException(20001,"密码不正确,登录失败");

}//判断用户是否禁用

if(mobileMember.getIsDisabled()){throw new GuliException(20001,"用户已禁用,登录失败");

}//登录成功,使用jwt工具类生成token

String jwtToken =JwtUtils.getJwtToken(mobileMember.getId(), mobileMember.getNickname());returnjwtToken;

}

}

5.swagger测试

java单点登录token_单点登录(token,JWT)_第1张图片

六.注册功能

1.编写实体类

packagecom.atguigu.educenter.entity.vo;importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;/*** author LiQinZhen

* date 2020/10/29

* description: 注册实体类*/@Data

@ApiModel(value="注册对象", description="注册对象")public classRegisterVo {

@ApiModelProperty(value= "昵称")privateString nickname;

@ApiModelProperty(value= "手机号")privateString mobile;

@ApiModelProperty(value= "密码")privateString password;

@ApiModelProperty(value= "验证码")privateString code;

}

2.在controller中创建注册的方法

//注册

@RequestMapping("/register")publicR registerUser(@RequestBody RegisterVo registerVo){

memberService.register(registerVo);returnR.ok();

}

3.在service创建注册方法

public interface UcenterMemberService extends IService{//实现登录

String login(UcenterMember member);//注册

voidregister(RegisterVo registerVo);

}

4.编写service的实现类Impl

packagecom.atguigu.educenter.service.impl;importcom.atguigu.commonutils.JwtUtils;importcom.atguigu.commonutils.MD5;importcom.atguigu.educenter.entity.UcenterMember;importcom.atguigu.educenter.entity.vo.RegisterVo;importcom.atguigu.educenter.mapper.UcenterMemberMapper;importcom.atguigu.educenter.service.UcenterMemberService;importcom.atguigu.servicebase.exceptionhandler.GuliException;importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.stereotype.Service;importorg.springframework.util.StringUtils;/***

* 会员表 服务实现类

*

*

*@authortestjava

*@since2020-10-28*/@Servicepublic class UcenterMemberServiceImpl extends ServiceImpl implementsUcenterMemberService {

//注入redis模板

@Autowired

RedisTemplateredisTemplate;//实现登录

@OverridepublicString login(UcenterMember member) {//获取手机号和密码

String mobile =member.getMobile();

String password=member.getPassword();//判断手机号和密码是否为空

if(StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)){throw new GuliException(20001,"手机号或者密码为空,登录失败");

}//判断手机号是否正确

QueryWrapper wrapper = new QueryWrapper<>();

wrapper.eq("mobile",mobile);

UcenterMember mobileMember=baseMapper.selectOne(wrapper);//判断查询的对象是否为空

if(mobileMember==null){//没有这个手机号

throw new GuliException(20001,"手机号不存在,登录失败");

}//判断密码是否正确

/**因为数据库中的密码是加密的,

* 所以需要先将传入的密码进行加密,

* 再和数据库的密码进行比较,

* 使用MD5加密*/

if(!MD5.encrypt(password).equals(mobileMember.getPassword())){throw new GuliException(20001,"密码不正确,登录失败");

}//判断用户是否禁用

if(mobileMember.getIsDisabled()){throw new GuliException(20001,"用户已禁用,登录失败");

}//登录成功,使用jwt工具类生成token

String jwtToken =JwtUtils.getJwtToken(mobileMember.getId(), mobileMember.getNickname());returnjwtToken;

}//注册方法

@Overridepublic voidregister(RegisterVo registerVo) {//获取注册的数据

String code = registerVo.getCode();//验证码

String mobile = registerVo.getMobile();//手机号

String nickname = registerVo.getNickname();//昵称

String password = registerVo.getPassword();//密码//非空判断

if(StringUtils.isEmpty(code)||StringUtils.isEmpty(mobile)||StringUtils.isEmpty(nickname)||StringUtils.isEmpty(password)){throw new GuliException(20001,"验证码,手机号,昵称或者密码为空,注册失败");

}//判断验证码是否正确,即发送到手机的验证码和数据库存的是否一样//获取redis中的验证码

String redisCode =redisTemplate.opsForValue().get(mobile);//比较输入的验证码和redis中的验证码是否一样

if(!code.equals(redisCode)){throw new GuliException(20001,"验证码不正确,注册失败");

}//判断手机号是否相同,如果表里面存在相同的手机号则不进行添加//先根据手机号在数据库查询数据

QueryWrapper wrapper = new QueryWrapper<>();

wrapper.eq("mobile",mobile);

Integer count=baseMapper.selectCount(wrapper);if(count>0){throw new GuliException(20001,"手机号已存在,注册失败");

}//数据添加到数据库

UcenterMember member = newUcenterMember();

member.setMobile(mobile);

member.setNickname(nickname);

member.setPassword(MD5.encrypt(password));

member.setAvatar("http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132");

member.setIsDisabled(false);

baseMapper.insert(member);

}

}

5.根据token获取用户信息

//根据token获取用户信息

@GetMapping("/getMemberInfo")publicR getMemberInfo(HttpServletRequest request){//调用jwt的方法,根据request对象获取头信息,返回用户id

String memberId =JwtUtils.getMemberIdByJwtToken(request);//查询数据库,根据用户id获取用户信息

UcenterMember member =memberService.getById(memberId);return R.ok().data("userInfo",member);

}

你可能感兴趣的:(java单点登录token)