JAVA全系列 教程
3762个小节阅读:7095.4k
目录
C语言快速入门
JAVA全系列 教程
面向对象的程序设计语言
Python全系列 教程
Python3.x版本,未来主流的版本
人工智能 教程
顺势而为,AI创新未来
大厂算法 教程
算法,程序员自我提升必经之路
C++ 教程
一门通用计算机编程语言
微服务 教程
目前业界流行的框架组合
web前端全系列 教程
通向WEB技术世界的钥匙
大数据全系列 教程
站在云端操控万千数据
AIGC全能工具班
A A
White Night
为什么要使用OAuth2?
OAuth2是一个关于授权的开放网络标准,允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用。OAuth在全世界得到广泛应用,目前的版本是2.0版。
业务系统中使用登录的几种形式
OAuth2中定义的几个角色
Resource owner 资源拥有者
可理解为用户本人
Resource Server 资源服务器
托管受保护资源的服务器,能够使用访问令牌接受和响应受保护资源请求
客户端
可理解为你想登录的网站或应用
Authentication Server 认证服务器
客户端向认证服务器申请令牌,认证服务器经验证通过后向客户端授权许可,可理解为第三方的QQ、微信服务器。
OAuth2授权认证流程
什么情况下需要使用OAuth2?
单点登录
项目中有多个微服务,需要一个专门的认证中心,所有服务都需要到认证中心进行认证,只做一次登录,就可以在授权范围内的多个服务之间来回穿行。
第三方授权登录
这种场景在一些网站登录时很常见,可以自行注册该网站的账户登录,也可使用第三方授权登录的方式,比如通过QQ,微博,等知名网站进行授权登录。
OAuth2的授权登录方式
授权码模式
这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。
密码式
如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用根据你的用户名和密码生成令牌,这种方式称为"密码式"。
Spring Cloud OAuth2 + JWT实现
在本项目的统一认证场景中,资源服务器就是我们各种受到保护的微服务,微服务中的各种API访问接口就是资源,发起http请求的浏览器就是client端。
实体类 LoginUser.java
xxxxxxxxxx
package com.itbaizhan.domain;
import ...
/**
*
* @TableName tb_login_user
*/
@TableName(value ="tb_login_user")
@Data
public class LoginUser implements Serializable {
/**
*
*/
@TableId(value = "id")
private Long id;
/**
*
*/
@TableField(value = "user_name")
private String userName;
/**
*
*/
@TableField(value = "password")
private String password;
/**
*
*/
@TableField(value = "update_time")
private Date updateTime;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
LoginUser other = (LoginUser) that;
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
&& (this.getUserName() == null ? other.getUserName() == null : this.getUserName().equals(other.getUserName()))
&& (this.getPassword() == null ? other.getPassword() == null : this.getPassword().equals(other.getPassword()))
&& (this.getUpdateTime() == null ? other.getUpdateTime() == null : this.getUpdateTime().equals(other.getUpdateTime()));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
result = prime * result + ((getUserName() == null) ? 0 : getUserName().hashCode());
result = prime * result + ((getPassword() == null) ? 0 : getPassword().hashCode());
result = prime * result + ((getUpdateTime() == null) ? 0 : getUpdateTime().hashCode());
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", userName=").append(userName);
sb.append(", password=").append(password);
sb.append(", updateTime=").append(updateTime);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();
}
}
数据传输对象DTO LoginDto、Result
xxxxxxxxxx
package com.itbaizhan.dto;
import lombok.Data;
@Data
public class LoginDto {
private String userName;
private String password;
}
xxxxxxxxxx
package com.itbaizhan.dto;
import lombok.Data;
/**
* 返回对象
*/
@Data
public class Result {
public Result(String access_token, String error, String error_description, String refresh_token, int expires_in) {
this.access_token = access_token;
this.error = error;
this.error_description = error_description;
this.refresh_token = refresh_token;
this.expires_in = expires_in;
}
private String access_token;
private String error;
private String error_description;
private String refresh_token;
private int expires_in;
}
登录控制器LoginController.java
xxxxxxxxxx
package com.itbaizhan.controller;
import ...
@Controller
public class LoginController {
@Autowired
private LoginUserService loginUserService;
@Autowired
@Qualifier("customerRestTemplate")
private RestTemplate restTemplate;
/**
* 转到登录页面
* @return
*/
@GetMapping("toLogin")
public ModelAndView toLogin(){
ModelAndView modelAndView = new ModelAndView("login");
return modelAndView;
}
/**
* 登录并请求令牌
* @param loginDto
* @return
*/
@PostMapping("login")
@ResponseBody
public Result login(@RequestBody LoginDto loginDto){
String client_secret = Constant.client_secret;
String grant_type_password = Constant.grant_type_pwd;
String client_id = Constant.client_id;
URI uri = URI.create(Constant.get_token_uri
+ "?client_secret=" + client_secret + "&"
+ "grant_type=" + grant_type_password + "&"
+ "username=" + loginDto.getUserName() + "&"
+ "password=" + loginDto.getPassword() + "&"
+ "client_id=" + client_id);
Result result = restTemplate.getForObject(uri, Result.class);
return result;
}
}
mapper接口,LoginUserMapper.java
xxxxxxxxxx
package com.itbaizhan.mapper;
import com.itbaizhan.domain.LoginUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author a
* @description 针对表【tb_login_user】的数据库操作Mapper
* @Entity com.itbaizhan.domain.LoginUser
*/
public interface LoginUserMapper extends BaseMapper<LoginUser> {
}
LoginUserService.java
xxxxxxxxxx
/* @author a
* @description 针对表【tb_login_user】的数据库操作Service
*/
public interface LoginUserService extends IService<LoginUser> {
LoginUser findByUsername(String userName);
}
Service实现类
xxxxxxxxxx
/**
* @author a
* @description 针对表【tb_login_user】的数据库操作Service实现
*/
@Service
public class LoginUserServiceImpl extends ServiceImpl<LoginUserMapper, LoginUser>
implements LoginUserService{
@Autowired
private LoginUserMapper loginUserMapper;
@Override
public LoginUser findByUsername(String userName) {
QueryWrapper<LoginUser> wrapper = new QueryWrapper<>();
wrapper.eq(StringUtils.isNotBlank(userName),"user_name", userName);
return loginUserMapper.selectOne(wrapper);
}
}
启动后登录页面