SpringBoot整合SSO(single sign on)单点登录

网友投稿 1063 2023-05-24

SpringBoot整合SSO(single sign on)单点登录

SpringBoot整合SSO(single sign on)单点登录

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

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

(2)使用Cookie+Redis实现

(3)使用token实现

2、单点登录介绍

举例:

(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、单点登录实现

项目目录结构

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、登录完成后在前端界面展示用户信息

(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 = "/";

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:组建基础设置无线局域网,一套代码,多端复用
下一篇:mybatis实现图书管理系统
相关文章

 发表评论

暂时没有评论,来抢沙发吧~