2019独角兽企业重金招聘Python工程师标准>>>

要进行单设备登录,在其他地点登录后,本地的其他操作会被拦截返回登录界面。

原理就在于要在登录时在redis中存储Session,进行操作时要进行Session的比对。

具体实现,假设我们的OAuth 2的登录调用接口如下:

共享Session,User模块跟OAuth模块都要设置

@Configuration
@EnableRedisHttpSession
public class SessionConfig {}

Feign

@Component
@FeignClient("oauth-center")
public interface Oauth2Client {/*** 获取access_token<br>* 这是spring-security-oauth2底层的接口,类TokenEndpoint<br>** @param parameters* @return* @see org.springframework.security.oauth2.provider.endpoint.TokenEndpoint*/@PostMapping(path = "/api-o/oauth/token")Map<String, Object> postAccessToken(@RequestParam Map<String, String> parameters);/*** 删除access_token和refresh_token<br>* 认证中心的OAuth2Controller方法removeToken** @param access_token*/@DeleteMapping(path = "/api-o/remove_token")void removeToken(@RequestParam("access_token") String access_token);}

Controller

/*** Created by Administrator on 2018/10/19.*/
@Slf4j
@RestController
public class UserTokenController {@Autowiredprivate Oauth2Client oauth2Client;@Resourceprivate RedisService redisServiceImpl;/*** 系统登陆<br>* 根据用户名登录<br>* 采用oauth2密码模式获取access_token和refresh_token** @param loginParam* @return*/@PostMapping("/users-anon/sys/logins")public Map<String, Object> login(@RequestBody LoginParam loginParam,HttpServletRequest request) {Map<String, String> parameters = new HashMap<>();parameters.put(OAuth2Utils.GRANT_TYPE, "password");parameters.put(OAuth2Utils.CLIENT_ID, "system");
//        parameters.put(OAuth2Utils.CLIENT_ID, "system");parameters.put("client_secret", "system");parameters.put(OAuth2Utils.SCOPE, "app");
//    parameters.put("username", username);// 为了支持多类型登录,这里在username后拼装上登录类型parameters.put("username", loginParam.getUsername() + "|" + CredentialType.USERNAME.name());parameters.put("password", loginParam.getPassword());parameters.put("status","200");Map<String, Object> tokenInfo = null;try {tokenInfo = oauth2Client.postAccessToken(parameters);}catch (Exception e){e.printStackTrace();return ResponseUtils.getResult(500,"login failed");}
//        saveLoginLog(username, "用户名密码登陆", BlackIPAccessFilter.getIpAddress(request));return ResponseUtils.getDataResult(tokenInfo);}
}

加入Session的存储

/*** Created by Administrator on 2018/10/19.*/
@Slf4j
@RestController
public class UserTokenController {@Autowiredprivate Oauth2Client oauth2Client;@Resourceprivate RedisService redisServiceImpl;/*** 系统登陆<br>* 根据用户名登录<br>* 采用oauth2密码模式获取access_token和refresh_token** @param loginParam* @return*/
@PostMapping("/users-anon/sys/logins")public Map<String, Object> login(@RequestBody LoginParam loginParam, HttpServletRequest request) {Map<String, String> parameters = new HashMap<>();parameters.put(OAuth2Utils.GRANT_TYPE, "password");parameters.put(OAuth2Utils.CLIENT_ID, "system");
//        parameters.put(OAuth2Utils.CLIENT_ID, "system");parameters.put("client_secret", "system");parameters.put(OAuth2Utils.SCOPE, "app");
//    parameters.put("username", username);// 为了支持多类型登录,这里在username后拼装上登录类型parameters.put("username", loginParam.getUsername() + "|" + CredentialType.USERNAME.name());parameters.put("password", loginParam.getPassword());parameters.put("status","200");Map<String, Object> tokenInfo = null;try {tokenInfo = oauth2Client.postAccessToken(parameters);HttpSession session = request.getSession();String sessionId = UUID.randomUUID().toString();//此处修改为共享Sessionsession.setAttribute("sessionId", sessionId);session.setAttribute("username",loginParam.getUsername());String key = loginParam.getUsername() + "-onlyLogin";redisServiceImpl.set(key,sessionId);redisServiceImpl.expire(key,30 * 60);redisServiceImpl.hset("sessionHash",sessionId,loginParam.getUsername());}catch (Exception e){e.printStackTrace();return ResponseUtils.getResult(500,"login failed");}
//        saveLoginLog(username, "用户名密码登陆", BlackIPAccessFilter.getIpAddress(request));return ResponseUtils.getDataResult(tokenInfo);}
}

配置拦截器

@Slf4j
@Component
public class RedisInterceptor extends HandlerInterceptorAdapter {@Resourceprivate RedisService redisServiceImpl;@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HttpSession session = request.getSession();//读取共享SessionString requestedSessionId = (String) session.getAttribute("sessionId");String userName = null;response.setCharacterEncoding("utf-8");response.setContentType("text/javascript;charset=utf-8");try {if (!StringUtils.isEmpty(requestedSessionId)) {userName = redisServiceImpl.hget("sessionHash", requestedSessionId);}if (StringUtils.isEmpty(userName)) {response.getWriter().write("{\"message\":\"请先登陆\"}");return false;} else {String cacheSessionId = null;String sessionKey = userName + "-onlyLogin";try {cacheSessionId = redisServiceImpl.get(sessionKey);} catch (Exception e) {e.printStackTrace();}if (StringUtils.isEmpty(cacheSessionId)) {response.getWriter().write("{\"message\":\"请先登陆\"}");return false;} else {if (!cacheSessionId.equals(requestedSessionId)) {response.getWriter().write("{\"message\":\"您的账号已在别处登陆,请重新登陆\"}");return false;} else {redisServiceImpl.expire(sessionKey, 30 * 60);return super.preHandle(request, response, handler);}}}}catch (Exception e) {e.printStackTrace();}response.getWriter().write("{\"message\":\"服务器忙\"}");return false;}
}

拦截器就是为了获取每次的Session,并且跟redis中的session进行比对,如果session不同,则进行拦截。

@Configuration
public class RedisSessionConfig extends WebMvcConfigurerAdapter {@Autowiredprivate RedisInterceptor redisInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(redisInterceptor).excludePathPatterns("/**/users-anon/**").excludePathPatterns("/api-o/oauth/token");super.addInterceptors(registry);}
}

这里要配置对登录的url以及feign的url进行放行,则可以对多地点登录时,使之前的登录无法操作。

转载于:https://my.oschina.net/u/3768341/blog/2885756

配合OAuth2进行单设备登录拦截相关推荐

  1. 基于token的登录管理(多设备登录、单设备登录)

    详情参见: https://gitee.com/xxssyyyyssxx/token 不管是客户端接口还是网页H5接口,一般我们都需要登录验证,即要求所有的接口访问都必须在登录之后,以确认身份,防止非 ...

  2. WebSocket + Redis简单快速实现Web网站单设备登录功能

    1.写在前面的话 生活中,我们在使用一些APP的时候,有过一种体验,就是在A手机上登录账号,因为某些原因需要在B手机上登录,然后就会在A手机上看到类似"该账号在其他设备登录"的提示 ...

  3. Laravel 单设备登录

    https://laravel-china.org/articles/10605/laravel-single-device-login 前几天在 laracasts 看了laravel5.6的新功能 ...

  4. 七、SpringBoot——用户登录Demo(国际化、表单重复提交,登录拦截器)

    一.CURD的Demo 1开发前准备工作 新建一个SpringBoot工程 引入starter-web maven依赖 引入html页面和assert文件夹里的样式文件等等 2 实现访问登录页面 方式 ...

  5. 基于Spring Security + OAuth2 的SSO单点登录(服务端)

    相关技术 spring security: 用于安全控制的权限框架 OAuth2: 用于第三方登录认证授权的协议 JWT:客户端和服务端通信的数据载体 传统登录 登录web系统后将用户信息保存在ses ...

  6. 使用Spring Secuirty Oauth2实现SSO单点登录

    文章目录 1. 什么是单点登录 2. 微服务架构下单点登录的思路 3. 使用 Spring Secuirty Oauth2 实现SSO单点登录 ①:建表 ②:授权服务器逻辑 ③:网关逻辑 4. 接口测 ...

  7. Oauth2.0实现单点登录的原理流程,这次总该懂了!

    单点登录是多域名企业站点流行的登录方式.本文以现实生活场景辅助理解,力争彻底理清 OAuth2.0 实现单点登录的原理流程.同时总结了权限控制的实现方案,及其在微服务架构中的应用. 1 什么是单点登录 ...

  8. Oauth2.0实现单点登录的原理流程

    Oauth2.0实现单点登录的原理流程 1.什么是单点登录 2.OAuth2 认证授权的原理流程 3.基于 SpringBoot 实现认证/授权 4.综合运用 1.什么是单点登录 1.1 多点登录 传 ...

  9. Oauth2.0实现单点登录的原理流程,通俗易懂

    单点登录是多域名企业站点流行的登录方式.本文以现实生活场景辅助理解,力争彻底理清 OAuth2.0 实现单点登录的原理流程.同时总结了权限控制的实现方案,及其在微服务架构中的应用. 1 什么是单点登录 ...

最新文章

  1. 北斗导航 | 卫星导航基础知识(卫星轨道及卫星在轨运动)
  2. .Net Crank性能测试入门
  3. 高效程序员应该养成的七个习惯
  4. 使用proguard混淆java web项目代码
  5. 八个led闪烁c语言程序,闪烁的LED
  6. Linux下安装Nginx与配置
  7. 「 机器人学 」“增量式/绝对式编码器”讲解
  8. 【强化学习】 Nature DQN算法与莫烦代码重现(tensorflow)
  9. YOLOv5训练自己的数据集(超详细完整版)
  10. 时间管理-番茄工作法
  11. 硬链接(hard link)与软链接(soft link/symbolic link)
  12. 舆情传染病时空分析文献阅读笔记
  13. java中io的重要性_java中的IO整理
  14. 关于react-router-dom 6.0.1的基础写法 解决Error: A <Route> is only ever to be used as the child of <Routes>
  15. 了解什么是架构基本概念和架构本质
  16. Matlab:向图中添加注释
  17. Seaborn系列| 绘制相关性热图(仅显示下三角相关性)
  18. 最新最全的免费股票数据接口--沪深A股深度分析机构持股数据API接口(十二)
  19. opencv回顾之路Imgproc Module
  20. 公司不开三方解约函怎么解决

热门文章

  1. html5 web storage攻击,HTML5安全风险详析之二:Web Storage攻击
  2. Linux学习:第五章-Linux用户和用户组管理
  3. 命运2服务器维护时间2019,《命运2》今晚将停机维护 为多平台共用存档做准备...
  4. leetcode485. 最大连续1的个数 *py:“又是一行就解决了,没意思”
  5. leetcode167. 两数之和 II - 并没有那么easy的easy题
  6. 《Python Cookbook 3rd》笔记(5.2):打印输出至文件中
  7. python开发web项目_Django2:Web项目开发入门笔记(20)
  8. C++primer 第 3 章 字符串、向量和数组 3 . 4 迭代器介绍
  9. 使用openssl完成aes-ecb模式的数据加解密,输入和输出都是字符串类型
  10. java 进制转换 十进制转二,八,十六进制