这个简单的demo主要有三个微服务组成:
sso为单点登录的请求服务,system_service为管理员登录验证服务,member为会员登录验证服务。
SSO
controller
/**
* @description: ssocontroller
* @return {@link null}
* @author wangxihao
* @email wangxh0108@163.com
**/
@RestController
@RequestMapping("/member")
public class MemberLoginController {
@Resource
private AuthenticationService remoteMemberService;
/**
* 登录
* @param userName
* @param password
* @return
*/
@GetMapping("/login")
public Result getMember(String userName,String password){
return new Result(ResultStatus.SUCCESS.getReturncode(), ResultStatus.SUCCESS.getReturnMessage(),remoteMemberService.checkUsernameAndPassword(userName,password));
}
/**
* 验证Token
* @param token
* @return
*/
@GetMapping("/reLogin")
public Result checkUser(String token){
if(remoteMemberService.checkToken(token)){
return new Result(ResultStatus.SUCCESS.getReturncode(), ResultStatus.SUCCESS.getReturnMessage(),"成功!");
}
return new Result(ResultStatus.ERROR.getReturncode(), ResultStatus.ERROR.getReturnMessage(),"失败!");
}
}
@RestController
@RequestMapping("/user")
public class UserLoginController {
@Resource
private AuthenticationService remoteUserService;
@GetMapping("/login")
public Result getUser(String userName,String passWord){
return new Result(ResultStatus.SUCCESS.getReturncode(), ResultStatus.SUCCESS.getReturnMessage(),remoteUserService.checkUsernameAndPassword(userName,passWord));
}
@GetMapping("/reLogin")
public Result checkUser(String token){
if(remoteUserService.checkToken(token)){
return new Result(ResultStatus.SUCCESS.getReturncode(), ResultStatus.SUCCESS.getReturnMessage(),"成功!");
}
return new Result(ResultStatus.ERROR.getReturncode(), ResultStatus.ERROR.getReturnMessage(),"失败!");
}
}
AuthenticationService 服务层
AuthenticationService 服务层 两个controller同调用这一层
public interface AuthenticationService {
/**
* 登录功能,校验用户名密码是否正确,正确生成token 返回并存入redis
* @param userName
* @param passWord
* @return
*/
Result checkUsernameAndPassword(String userName, String passWord);
/**
* 验证token
* @param token
* @return
*/
boolean checkToken(String token);
}
AuthenticationService 两个实现类:
@Service("remoteMemberService")
public class RemoteMemberServiceImpl implements AuthenticationService {
@Autowired
private RedisTemplate redisTemplate;
@Override
public Result checkUsernameAndPassword(String userName, String password) {
//判断同户名密码是否空
if(!StringUtils.hasText(userName)||!StringUtils.hasText(password)){
throw new CustomException(ResultStatus.ARGUMENT_IS_NOT_NULL.getReturncode(),
ResultStatus.ARGUMENT_IS_NOT_NULL.getReturnMessage());
}
//手机用户信息
CustomUsernamePasspordToken customUsernamePasspordToken = new CustomUsernamePasspordToken(userName, password, LoginType.MEMBER.toString());
//获取subject
Subject subject = SecurityUtils.getSubject();
try {
subject.login(customUsernamePasspordToken);
//获取用户信息
Member member = (Member) subject.getPrincipal();
String token = member.getUsername()+ UUID.randomUUID().toString();
// 设置放入redis后key序列化方式,使用字符串 key是是什么放入的就是什么
redisTemplate.setKeySerializer(RedisSerializer.string());
// 使用Redis 字符串操作,放入对象 方便后面使用token换取用户信息
redisTemplate.opsForValue().set(token,member);
return new Result(ResultStatus.SUCCESS.getReturncode(),ResultStatus.SUCCESS.getReturnMessage(),token);
} catch (AuthenticationException e) {
e.printStackTrace();
}
return new Result(ResultStatus.ERROR.getReturncode(),
ResultStatus.ERROR.getReturnMessage(),"用户名或者密码错误!");
}
@Override
public boolean checkToken(String token) {
return redisTemplate.hasKey(token);
}
}
@Service("remoteUserService")
public class RemoteUserServiceImpl implements AuthenticationService {
@Autowired
private RedisTemplate redisTemplate;
@Override
public Result checkUsernameAndPassword(String userName, String passWord) {
//判断同户名密码是否空
if(!StringUtils.hasText(userName)||!StringUtils.hasText(passWord)){
throw new CustomException(ResultStatus.ARGUMENT_IS_NOT_NULL.getReturncode(),
ResultStatus.ARGUMENT_IS_NOT_NULL.getReturnMessage());
}
//手机用户信息
CustomUsernamePasspordToken customUsernamePasspordToken = new CustomUsernamePasspordToken(userName, passWord, LoginType.USER.toString());
//获取subject
Subject subject = SecurityUtils.getSubject();
try {
subject.login(customUsernamePasspordToken);
//获取用户信息
User user = (User) subject.getPrincipal();
String token = user.getUserName()+ UUID.randomUUID().toString();
// 设置放入redis后key序列化方式,使用字符串 key是是什么放入的就是什么
redisTemplate.setKeySerializer(RedisSerializer.string());
// 使用Redis 字符串操作,放入对象 方便后面使用token换取用户信息
redisTemplate.opsForValue().set(token,user);
return new Result(ResultStatus.SUCCESS.getReturncode(),ResultStatus.SUCCESS.getReturnMessage(),token);
} catch (AuthenticationException e) {
e.printStackTrace();
}
return new Result(ResultStatus.ERROR.getReturncode(),
ResultStatus.ERROR.getReturnMessage(),"用户名或者密码错误!");
}
@Override
public boolean checkToken(String token) {
return redisTemplate.hasKey(token);
}
}
重写Realm的验证
这个类注意别忘了加入Bean容器中
/**
* @description: 自定义验证realm的方法 重写源码中
*
* @return {@link null}
* @author wangxihao
* @email wangxh0108@163.com
**/
public class CustomModularRealmAuthenticator extends ModularRealmAuthenticator {
@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
//断言判断是否存在realm
this.assertRealmsConfigured();
//向下转型 authenticationToken转为自定义的
CustomUsernamePasspordToken customUsernamePasspordToken = (CustomUsernamePasspordToken) authenticationToken;
//得到登录类型 admin tiger LoginType.USER("user")
String loginType = customUsernamePasspordToken.getLoginType();
//得到真正配置的Realm并判断 (UserRealm MemberRealm)
Collection<Realm> realms = this.getRealms();
//定义Realm集合
ArrayList<Realm> customRealm = new ArrayList<>();
//遍历Realm
for (Realm realm : realms) {
//判断当前Realm名称中是否包含User or Member
if(realm.getName().toLowerCase().contains(loginType.toLowerCase())){
customRealm.add(realm);
}
}
//有一个Realm的话 将当前realms.iterator().next()传入 多个的话 将 realms集合传入
return realms.size() == 1 ? this.doSingleRealmAuthentication(realms.iterator().next(), customUsernamePasspordToken) : this.doMultiRealmAuthentication(realms, customUsernamePasspordToken);
}
}
自定义Realm
public class MemberRealm extends AuthorizingRealm {
@Autowired
private RemoteMemberService remoteMemberService;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String userName = authenticationToken.getPrincipal().toString();
System.out.println("用户名"+userName);
Member realMember = remoteMemberService.queryByUsername(userName);
if(realMember == null){
throw new AccountException();
}
System.out.println(realMember);
return new SimpleAuthenticationInfo(realMember,realMember.getPassword(),getName());
}
}
public class UserRealm extends AuthorizingRealm {
@Autowired
private RemoteUserService remoteUserService;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String userName = authenticationToken.getPrincipal().toString();
System.out.println("用户名"+userName);
User realUser = remoteUserService.queryByUserName(userName);
if(realUser == null){
throw new AccountException();
}
return new SimpleAuthenticationInfo(realUser,realUser.getPassword(),getName());
}
}
自定义Token
/**
* @description: 收集是用户信息还是会员信息 使用UsernamePasswordToken时重新父类的方法添加属性
*
* @return {@link null}
* @author wangxihao
* @email wangxh0108@163.com
**/
@Data
public class CustomUsernamePasspordToken extends UsernamePasswordToken {
//登录类型
private String loginType;
//构造器中调用父类构造 并添加子类构造中的属性
public CustomUsernamePasspordToken(String username, String password, String loginType) {
super(username, password);
this.loginType = loginType;
}
}
shiro配置
@Configuration
public class SpringShiroConfig {
/**
* 实例化ShiroFilterFactoryBean 拦截到所有的请求,根据请求的不同做不同的处理
* 配置处理请求的各种方式,配置SecurityManager 等等
* @return
*/
@Bean //<bean id=shiroFilter class = org.apache.shiro.spring.web.ShiroFilterFactoryBean>
public ShiroFilterFactoryBean shiroFilter(){
//实例化ShiroFilterFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//依赖注入
shiroFilterFactoryBean.setSecurityManager(securityManager());
//定义一个map集合 LinkedHashMap 按照放入顺序进行获取
Map chainDefinitionMap = new LinkedHashMap();
//所有功能放心 前后端分离认证拦截是基于session 每次请求的session不同
chainDefinitionMap.put("/**","anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(chainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 实例化shiro核心概念类 DefaultWebSecurityManager
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager(){
DefaultWebSecurityManager securityManager =new DefaultWebSecurityManager();
ArrayList<Realm> realms = new ArrayList<>();
realms.add(userRealm()); //UserRealm
realms.add(memberRealm()); //MemberRealmx1
//依赖注入Realm
securityManager.setRealms(realms);
return securityManager;
}
/**
* 配置realm 获取安全数据类
* @return
*/
@Bean
public UserRealm userRealm(){
UserRealm userRealm =new UserRealm();
return userRealm;
}
@Bean
public MemberRealm memberRealm(){
MemberRealm memberRealm =new MemberRealm();
return memberRealm;
}
Feign远程调用(也可以直接查数据库,没必要远程调用)
@FeignClient("MemberServer")
public interface RemoteMemberService {
/**
* 远程调用member
*/
@GetMapping("/member/queryByUsername")
public Member queryByUsername(@RequestParam("userName") String userName);
}
@FeignClient("SystemServer")
public interface RemoteUserService {
/**
* 远程调用member
*/
@GetMapping("/user/queryByUserName")
public User queryByUserName(@RequestParam("userName")String userName);
}
application.yml
#端口号
server:
port: 14860
spring:
application:
#服务名称 注册后的名称
name: SsoServer
cloud:
nacos:
discovery:
#nacos注册中心地址
server-addr: localhost:8848
#redis配置 RedisTemplate可以直接使用这些配置
redis:
#集群配置
#cluster:
# nodes: 192.168.170.41:6001,192.168.170.41:6002,192.168.170.42:6003,192.168.170.42:6004,192.168.170.43:6005,192.168.170.43:6006
#单机版配置
host: 127.0.0.1
port: 6379
#连接属性配置
database: 0
timeout: 30000ms
jedis:
pool:
max-active: 20000
max-idle: 0
max-wait: 20000ms
main:
allow-bean-definition-overriding: true
#swagger配置
swagger:
base-package: com.aaa.sso.controller
title: "电商项目-单点登录swagger"
description: "描述"
version: "3.0"
contact:
name: "AAA"
email: "test@163.com"
url: "https://www.baidu.com"
terms-of-service-url: "服务条款:https://www.baidu.com"
其他两个服务我就不写了,就是一个远程调用查数据库。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/75446.html