- 分布式,SSO(single sign on)模式
解决 :
1.用户身份信息独立管理,更好的分布式管理。
2.可以自己扩展安全策略
3,跨域不是问题
缺点:
1.认证服务器访问压力较大。
- 单点登录流程图
3.UmsMember.java
public class UmsMember implements Serializable {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private String id;
private String memberLevelId;
private String username;
private String password;
private String nickname;
private String phone;
private int status;
private Date createTime;
private String icon;
private String gender;
private Date birthday;
private String city;
private String job;
private String personalizedSignature;
private String sourceType;
private int integration;
private int growth;
private int luckeyCount;
private int historyIntegration;
private Long sourceUid;
private String accessToken;
private String accessCode;
4.UmsService.java
public interface UserService {
List<UmsMember> getAllUser();
List<UmsMemberReceiveAddress> getUmsMemberReceiveAddress(String memberId);
UmsMember login(UmsMember umsMember);
void addUserToken(String token, String memberId);
UmsMember addOldOauthUser(UmsMember umsMember);
UmsMember checkOauthUser(UmsMember umsCheck);
UmsMemberReceiveAddress getReceiveAddressById(String receiveAddressId);
}
4.UserMapper.java
public interface UserMapper extends Mapper<UmsMember>{
List<UmsMember> selectAllUser();
}
5.UmsMemberReceiveAddressMapper.java
public interface UmsMemberReceiveAddressMapper extends Mapper<UmsMemberReceiveAddress>{
}
6.UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private UmsMemberReceiveAddressMapper umsMemberReceiveAddressMapper;
@Autowired
RedisUtil redisUtil;
@Override
public List<UmsMember> getAllUser() {
List<UmsMember> umsMemberList= userMapper.selectAll();
return umsMemberList;
}
@Override
public List<UmsMemberReceiveAddress> getUmsMemberReceiveAddress(String memberId) {
UmsMemberReceiveAddress umsMemberReceiveAddress=new UmsMemberReceiveAddress();
umsMemberReceiveAddress.setMemberId(memberId);
List<UmsMemberReceiveAddress> umsMemberReceiveAddresses = umsMemberReceiveAddressMapper.select(umsMemberReceiveAddress);
return umsMemberReceiveAddresses;
}
@Override
public UmsMember login(UmsMember umsMember) {
Jedis jedis=null;
try {
jedis = redisUtil.getJedis();
if(jedis!=null){
String umsMemberStr = jedis.get("user:" + umsMember.getPassword() + ":info");
if (StringUtils.isNotBlank(umsMemberStr)) {
//密码正确
UmsMember umsMemberFromCache = JSON.parseObject(umsMemberStr, UmsMember.class);
return umsMemberFromCache;
}
}
//连接redis失败,开启数据库
UmsMember umsMemberFromDb= loginFromDb(umsMember);
if(umsMemberFromDb!=null){
jedis.setex("user:" + umsMember.getPassword() +umsMember.getUsername()+ ":info",60*60*24,JSON.toJSONString(umsMemberFromDb));
}
return umsMemberFromDb;
}finally {
jedis.close();
}
}
@Override
public void addUserToken(String token, String memberId) {
Jedis jedis = redisUtil.getJedis();
jedis.setex("user:"+memberId+":token",60*60*2,token);
jedis.close();
}
@Override
public UmsMember addOldOauthUser(UmsMember umsMember) {
userMapper.insertSelective(umsMember);
return umsMember;
}
@Override
public UmsMember checkOauthUser(UmsMember umsCheck) {
UmsMember umsMember = userMapper.selectOne(umsCheck);
return umsMember;
}
@Override
public UmsMemberReceiveAddress getReceiveAddressById(String receiveAddressId) {
UmsMemberReceiveAddress umsMemberReceiveAddress=new UmsMemberReceiveAddress();
umsMemberReceiveAddress.setId(receiveAddressId);
UmsMemberReceiveAddress memberReceiveAddress = umsMemberReceiveAddressMapper.selectOne(umsMemberReceiveAddress);
return memberReceiveAddress;
}
private UmsMember loginFromDb(UmsMember umsMember) {
List<UmsMember> umsMembers = userMapper.select(umsMember);
if(umsMembers!=null){
return umsMembers.get(0);
}
return null;
}
}
7.PassPortController.java
@Controller
public class PassPortController {
@Reference
UserService userService;
@RequestMapping("vlogin")
public String vlogin(String code,HttpServletRequest request){
//授权码换取access_token
String s3="https://api.weibo.com/oauth2/access_token?";
//?client_id=3193708961&client_secret=df2b2370fbd3483cdd8a9eb422ca325&grant_type=authorization_code&redirect_uri=http://passport.gmall.com:8085/vlogin&code=CODE";
HashMap<String, String> paramMap = new HashMap<>();
paramMap.put("client_id","3193708961");
paramMap.put("client_secret","df2b2370fbd3483cdd8a9eb422ca3253");
paramMap.put("grant_type","authorization_code");
paramMap.put("redirect_uri","http://passport.gmall.com:8085/vlogin");
paramMap.put("code",code);
String access_token_json = HttpclientUtil.doPost(s3, paramMap);
Map<String,String> access_map = JSON.parseObject(access_token_json, Map.class);
//access_token获取用户信息
String access_token = access_map.get("access_token");
String uid = access_map.get("uid");
String s4="https://api.weibo.com/2/users/show.json?access_token="+access_token+"&uid="+uid;
String s = HttpclientUtil.doGet(s4);
Map<String,Object> map = JSON.parseObject(s, Map.class);
//将用户信息保存到数据库,将用户类型设置为微博用户
UmsMember umsMember = new UmsMember();
umsMember.setSourceType("2");
umsMember.setAccessCode(code);
umsMember.setAccessToken(access_token);
umsMember.setNickname((String)map.get("screen_name"));
umsMember.setSourceUid(((Long)map.get("id")));
umsMember.setCity((String) map.get("location"));
umsMember.setGender((String) (map.get("gender")));
UmsMember umsCheck = new UmsMember();
umsCheck.setSourceUid(umsMember.getSourceUid());
UmsMember checkUmsMember = userService.checkOauthUser(umsCheck);
if(checkUmsMember==null){
umsMember=userService.addOldOauthUser(umsMember);
}else{
umsMember=umsCheck;
}
//生成JWT的token,并且重定向到首页,携带token
String token=null;
//rpc主键返回策略失效
String memberId = umsMember.getId();
String nickname = umsMember.getNickname();
Map<String,Object> userMap=new HashMap<>();
userMap.put("memberId",memberId);
userMap.put("nickname",nickname);
String ip = request.getHeader("x-forwarded-for");
//从request中获取IP
if(StringUtils.isBlank(ip)) {
ip=request.getRemoteAddr();
if(StringUtils.isBlank(ip)) {
ip="127.0.0.1";
}
}
//按照设计的算法对参数进行加密后,生成token
token = JwtUtil.encode("2019gmall0105", userMap, ip);
return "redirect:http://search.gmall.com:8083/index?token="+token;
}
@RequestMapping("verify")
@ResponseBody
public String verify(String token,String currentIp){
//通过jwt校验token真假
Map<String,String> map=new HashMap<>();
Map<String, Object> decode = JwtUtil.decode(token, "2019gmall0105", currentIp);
if(decode!=null) {
map.put("status", "success");
map.put("memberId", (String) decode.get("memberId"));
map.put("nickName", (String) decode.get("nickName"));
}else{
map.put("status", "fail");
}
return JSON.toJSONString(map);
}
@RequestMapping("login")
@ResponseBody
public String login(UmsMember umsMember, HttpServletRequest request){
String token="";
//调用用户服务验证用户名和密码
UmsMember userMemberLogin= userService.login(umsMember);
if(userMemberLogin!=null){
//登陆成功
//用jwt制作token
//将token存入redis一份
String memberId = userMemberLogin.getId();
String nickname = userMemberLogin.getNickname();
Map<String,Object> userMap=new HashMap<>();
userMap.put("memberId",memberId);
userMap.put("nickname",nickname);
String ip = request.getHeader("x-forwarded-for");
//从request中获取IP
if(StringUtils.isBlank(ip)) {
ip=request.getRemoteAddr();
if(StringUtils.isBlank(ip)) {
ip="127.0.0.1";
}
}
//按照设计的算法对参数进行加密后,生成token
token = JwtUtil.encode("2019gmall0105", userMap, ip);
//将token放入redis一份
userService.addUserToken(token,memberId);
}else{
//登陆失败
token="fail";
}
return token;
}
@RequestMapping("index")
public String index(String ReturnUrl, ModelMap map){
map.put("ReturnUrl",ReturnUrl);
return "index";
}
}
6.AuthInterceptor.java拦截器
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/**
* 拦截代码
*/
//判断被拦截请求的访问方法的注解是否需要拦截
HandlerMethod mh = (HandlerMethod) handler;
LoginRequired methodAnnotation = mh.getMethodAnnotation(LoginRequired.class);
StringBuffer url = request.getRequestURL();
//是否拦截
if(methodAnnotation==null){
return true;
}
String token="";
String oldToken = CookieUtil.getCookieValue(request, "oldToken", true);
if(StringUtils.isNotBlank(oldToken)){
token=oldToken;
}
String newToken = request.getParameter("token");
if(StringUtils.isNotBlank(newToken)){
token=newToken;
}
/**
* 该请求是否登录成功
*/
boolean loginSuccess = methodAnnotation.loginSuccess();
//请用认证中心进行验证
String success="fail";
Map<String,String> successMap=new HashMap<String, String>();
if(StringUtils.isNotBlank(token)){
String ip = request.getHeader("x-forwarded-for");
//从request中获取IP
if(StringUtils.isBlank(ip)) {
ip=request.getRemoteAddr();
if(StringUtils.isBlank(ip)) {
ip="127.0.0.1";
}
}
String successJson = HttpclientUtil.doGet("http://passport.gmall.com:8085/verify?token=" + token+"¤tIp="+ip);
successMap = JSON.parseObject(successJson, Map.class);
success=successMap.get("status");
}
if(loginSuccess){
//必须登陆成功才能使用
if(!success.equals("success")){
//重定向passport登陆
StringBuffer requestURL = request.getRequestURL();
response.sendRedirect("http://passport.gmall.com:8085/index?ReturnUrl="+requestURL);
return false;
}
//验证通过,覆盖token
request.setAttribute("memberId",successMap.get("memberId"));
request.setAttribute("nickname",successMap.get("nickName"));
//验证通过,覆盖cookie里的token
if(StringUtils.isNotBlank(token)) {
CookieUtil.setCookie(request, response, "oldToken", token, 60 * 60 * 2, true);
}
}else{
//没有登陆也可以用,但是必须校验
if(success.equals("success")){
//重定向passport登陆
request.setAttribute("memberId",successMap.get("memberId"));
request.setAttribute("nickname",successMap.get("nickName"));
}
}
return true;
}
}
7.application.properties
server.port=8070
#jdbc 配置
spring.datasource.url=jdbc:mysql://localhost:3306/crm?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=09091995aq
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
mybatis.configuration.map-underscore-to-camel-case=true
#设置日志级别
logging.level.root=info
#扫描dubbo的配置
#dubbo中的服务名称
spring.dubbo.application=user-service
#dubbo的通讯协议名称
spring.dubbo.protocol.name=dubbo
#zookeeper注册中心地址
spring.dubbo.registry.address=47.101.36.177:2181
#zookeeper的注册名称
spring.dubbo.registry.protocol=zookeeper
#dubbo服务的扫描路径
spring.dubbo.base-package=com.atguigu.gmall
spring.dubbo.protocol.port=20880
#spring整合redis
#取配置文件中的redis的ip地址
#Redis数据库连接配置
spring.redis.host=47.101.36.177
spring.redis.port=6379
spring.redis.password=123
spring.redis.timeout=1000
spring.redis.database=0
8.GmallUserServiceApplication.java
@SpringBootApplication
@MapperScan(basePackages = "com.atguigu.gmall.user.mapper")
public class GmallUserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GmallUserServiceApplication.class, args);
}
}