java sso集成,SpringBoot整合SSO(single sign on)单点登录

1、单点登录三种常见的方式

(1)Session广播机制(Session复制)

(2)使用Cookie+Redis实现

(3)使用token实现

91a4b13c92007e1f21bfef54888ad2f4.png

2、单点登录介绍

f8fcf33634d3e87751d6aaccbdcdadbf.png

66d3a9b3a07bf3dbbab7bdd0440a452b.png

001495cc2b65f854b0f8011a2f9cbb84.png

d5829c2a1cf902d25ff610f8e878e224.png

举例:

2bed981b07a4facd773339adaae359ba.png

(1)引入jwt依赖

io.jsonwebtoken

jjwt

(2)创建JWTUtils工具类

public class JwtUtils {

//token过期时间

public static final long EXPIRE = 1000 * 60 * 60 * 24;

//秘钥

public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";

public static String getJwtToken(String id, String nickname){

String JwtToken = Jwts.builder()

//设置头信息

.setHeaderParam("typ", "JWT")

.setHeaderParam("alg", "HS256")

.setSubject("user")

.setIssuedAt(new Date())

//设置过期时间

.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))

//设置token主体部分(这里使用id和nickname作为主体部分)

.claim("id", id)

.claim("nickname", nickname)

//加密方式

.signWith(SignatureAlgorithm.HS256, APP_SECRET)

.compact();

return JwtToken;

}

/**

* 判断token是否存在与有效(直接通过APP_SECRET解析token)

* @param jwtToken

* @return

*/

public static boolean checkToken(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是否存在与有效(通过获取请求头信息获取token再使用APP_SECRET解析token)

* @param request

* @return

*/

public static boolean checkToken(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(取出有效载荷中的用户信息)

* @param request

* @return

*/

public static String 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");

}

}

3、单点登录实现

项目目录结构

73873b87a90d741e62aaf06fd95bf335.png

UcenterMemberController

@RestController

@RequestMapping("/user/")

@CrossOrigin

public class UcenterMemberController {

@Autowired

private UcenterMemberService ucenterMemberService;

//登录

@PostMapping("login")

public ResponseResult login(@RequestBody MobileLoginRequest request) {

String token = ucenterMemberService.login(request);

return ResponseResult.success().data("token", token);

}

//注册

@PostMapping("register")

public ResponseResult register(@RequestBody RegisterRequest request) {

ucenterMemberService.register(request);

return ResponseResult.success().message("注册成功");

}

//根据token获取用户信息

@GetMapping("getUserInfo")

public ResponseResult getUserInfo(HttpServletRequest request) {

//调用jwt工具类的方法,根据request对象获取头信息,返回用户id

String id = JwtUtils.getMemberIdByJwtToken(request);

//根据用户id查询用户

UcenterMember member = ucenterMemberService.getById(id);

return ResponseResult.success().data("userInfo", member);

}

}

ServiceImpl

@Service

public class UcenterMemberServiceImpl extends ServiceImpl implements UcenterMemberService {

@Autowired

private StringRedisTemplate redisTemplate;

//登录

@Override

public String login(MobileLoginRequest request) {

String phone = request.getPhone();

String password = request.getPassword();

if (StrUtil.isBlank(phone) || StrUtil.isBlank(password)) {

throw new GuliException(200001, "请输入用户名或者密码");

}

//根据输入的手机号码查找该用户信息

UcenterMember ucenterByPhone = this.baseMapper.selectOne(new LambdaQueryWrapper().eq(UcenterMember::getMobile, phone));

if (ucenterByPhone == null) {

throw new GuliException(200002, "该用户名不存在");

}

//如果用户存在比对数据库密码和用户输入的密码

if (!MD5Util.encrypt(password).equals(ucenterByPhone.getPassword())) {

throw new GuliException(200003, "密码输入错误");

}

String token = JwtUtils.getJwtToken(ucenterByPhone.getId(), ucenterByPhone.getNickname());

return token;

}

//注册

@Override

public void register(RegisterRequest request) {

String phone = request.getPhone();

String password = request.getPassword();

String nickName = request.getNickName();

String code = request.getCode();

if (StrUtil.isBlank(phone) || StrUtil.isBlank(password) || StrUtil.isBlank(nickName) || StrUtil.isBlank(code)) {

throw new GuliException(200001, "请填写相关信息");

}

//判断手机号是否重复

Integer count = baseMapper.selectCount(new LambdaQueryWrapper().eq(UcenterMember::getMobile, phone));

if (count > 0) {

throw new GuliException(200001, "账号已经存在请重新输入");

}

//验证code

String redisCode = redisTemplate.opsForValue().get(phone);

if (StrUtil.isBlank(redisCode)) {

throw new GuliException(200001, "验证码已经过期,请重新获取");

}

if (!redisCode.equals(code)) {

throw new GuliException(200001, "验证码错误");

}

UcenterMember ucenterByPhone = new UcenterMember();

ucenterByPhone.setMobile(phone);

ucenterByPhone.setPassword(MD5Util.encrypt(password));

ucenterByPhone.setNickname(nickName);

ucenterByPhone.setIsDisabled(false);

int insert = baseMapper.insert(ucenterByPhone);

if(insert<=0){

throw new GuliException(20001,"注册失败");

}

}

}

MD5加密算法工具类

public final class MD5Util {

public static String encrypt(String strSrc) {

try {

char hexChars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8',

'9', 'a', 'b', 'c', 'd', 'e', 'f'};

byte[] bytes = strSrc.getBytes();

MessageDigest md = MessageDigest.getInstance("MD5");

md.update(bytes);

bytes = md.digest();

int j = bytes.length;

char[] chars = new char[j * 2];

int k = 0;

for (int i = 0; i < bytes.length; i++) {

byte b = bytes[i];

chars[k++] = hexChars[b >>> 4 & 0xf];

chars[k++] = hexChars[b & 0xf];

}

return new String(chars);

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

throw new RuntimeException("MD5加密出错!!+" + e);

}

}

public static void main(String[] args) {

System.out.println(MD5Util.encrypt("111111"));

}

}

4、登录完成后在前端界面展示用户信息

3add3b27b41124177d9bdc84b7661502.png

(1)第一、二、四步:登录的方法(记得npm install js-cookie)

//登录的方法

submitLogin() {

//第一步 调用接口进行登录,返回token字符串

loginApi.submitLoginUser(this.user)

.then(response => {

//第二步 获取token字符串放到cookie里面

//第一个参数cookie名称,第二个参数值,第三个参数作用范围

cookie.set('user_token',response.data.data.token,{domain: 'localhost'})

//第四步 调用接口 根据token获取用户信息,为了首页面显示

loginApi.getLoginUserInfo()

.then(response => {

this.loginInfo = response.data.data.userInfo

//获取返回用户信息,放到cookie里面(主页在cookie中获取用户信息进行展示)

cookie.set('user_info',this.loginInfo,{domain: 'localhost'})

//跳转页面

window.location.href = "/";

})

})

},

(2)第三步:在request.js中编写前端请求拦截器(发送请求携带token)

// 创建axios实例

const service = axios.create({

baseURL: process.env.BASE_API, // api 的 base_url

timeout: 5000 // 请求超时时间

})

// request拦截器

service.interceptors.request.use(

config => {

if (cookie.get('user_token')) {

config.headers['token'] = cookie.get('user_token') // 让每个请求携带自定义token 请根据实际情况自行修改

}

return config

},

error => {

// Do something with request error

console.log(error) // for debug

Promise.reject(error)

}

)

(3)第五步:主页显示用户信息(从cookie中获取用户信息)

//创建方法,从cookie获取用户信息

showInfo() {

//从cookie获取用户信息

var userStr = cookie.get('guli_ucenter')

// 把字符串转换json对象(js对象),因为后端传过来的是"{'name','lucy','age':18}"的格式

if(userStr) {

this.loginInfo = JSON.parse(userStr)

}

}

显示用户信息(根据userInfo中id来判断)

//cookie中没有用户信息,显示登录和注册

登录

|

注册

//cookie中有用户信息,显示用户头像、昵称和退出

:src="loginInfo.avatar"

width="30"

height="30"

class="vam picImg"

alt

>

{{ loginInfo.nickname }}

退出

退出登录,清空cookie中的token和用户信息

//退出

logout() {

//清空cookie值

cookie.set('user_token','',{domain: 'localhost'})

cookie.set('user_info','',{domain: 'localhost'})

//回到首页面

window.location.href = "/";

}

}

到此这篇关于SpringBoot整合SSO(single sign on)单点登录的文章就介绍到这了,更多相关SpringBoot整合SSO单点登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值