多realm登录方式

This commit is contained in:
huhao1991 2019-06-04 10:25:52 +08:00
parent d4b353d8f2
commit 47862f692d
10 changed files with 576 additions and 169 deletions

View File

@ -2,6 +2,9 @@ package com.ruoyi.web.controller.system;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.framework.shiro.LoginType;
import com.ruoyi.framework.shiro.UserToken;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
@ -17,7 +20,7 @@ import com.ruoyi.common.utils.StringUtils;
/**
* 登录验证
*
*
* @author ruoyi
*/
@Controller
@ -39,22 +42,9 @@ public class SysLoginController extends BaseController
@ResponseBody
public AjaxResult ajaxLogin(String username, String password, Boolean rememberMe)
{
UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);
Subject subject = SecurityUtils.getSubject();
try
{
subject.login(token);
return success();
}
catch (AuthenticationException e)
{
String msg = "用户或密码错误";
if (StringUtils.isNotEmpty(e.getMessage()))
{
msg = e.getMessage();
}
return error(msg);
}
// UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);
UserToken token = new UserToken(username, password, rememberMe, LoginType.USER_PASSWORD);
return shiroLogin(token);
}
@GetMapping("/unauth")
@ -62,4 +52,35 @@ public class SysLoginController extends BaseController
{
return "error/unauth";
}
/**
* 手机验证码登录
* 由于是demo演示此处不添加发送验证码方法
* 正常操作发送验证码至手机并且将验证码存放在redis中登录的时候比较用户穿过来的验证码和redis中存放的验证码
*
* @param phone
* @param code
* @return
*/
@PostMapping("/phoneLogin")
@ResponseBody
public AjaxResult phoneLogin(String phone, String code) {
// 此处phone替换了usernamecode替换了password
UserToken token = new UserToken(phone, code, LoginType.USER_PHONE);
return shiroLogin(token);
}
public AjaxResult shiroLogin(UserToken token) {
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
return success();
} catch (AuthenticationException e) {
String msg = "用户或密码错误";
if (StringUtils.isNotEmpty(e.getMessage())) {
msg = e.getMessage();
}
return error(msg);
}
}
}

View File

@ -1,28 +1,12 @@
package com.ruoyi.framework.config;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.shiro.LoginType;
import com.ruoyi.framework.shiro.MyModularRealmAuthenticator;
import com.ruoyi.framework.shiro.realm.AuthorizationRealm;
import com.ruoyi.framework.shiro.realm.UserPhoneRealm;
import com.ruoyi.framework.shiro.realm.UserRealm;
import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
import com.ruoyi.framework.shiro.session.OnlineSessionFactory;
@ -32,16 +16,41 @@ import com.ruoyi.framework.shiro.web.filter.online.OnlineSessionFilter;
import com.ruoyi.framework.shiro.web.filter.sync.SyncOnlineSessionFilter;
import com.ruoyi.framework.shiro.web.session.OnlineWebSessionManager;
import com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 权限配置加载
*
*
* @author ruoyi
*/
@Configuration
public class ShiroConfig
{
public class ShiroConfig {
public static final String PREMISSION_STRING = "perms[\"{0}\"]";
// Session超时时间单位为毫秒默认30分钟
@ -84,17 +93,13 @@ public class ShiroConfig
* 缓存管理器 使用Ehcache实现
*/
@Bean
public EhCacheManager getEhCacheManager()
{
public EhCacheManager getEhCacheManager() {
net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi");
EhCacheManager em = new EhCacheManager();
if (StringUtils.isNull(cacheManager))
{
if (StringUtils.isNull(cacheManager)) {
em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));
return em;
}
else
{
} else {
em.setCacheManager(cacheManager);
return em;
}
@ -103,24 +108,18 @@ public class ShiroConfig
/**
* 返回配置文件流 避免ehcache配置文件一直被占用无法完全销毁项目重新部署
*/
protected InputStream getCacheManagerConfigFileInputStream()
{
protected InputStream getCacheManagerConfigFileInputStream() {
String configFile = "classpath:ehcache/ehcache-shiro.xml";
InputStream inputStream = null;
try
{
try {
inputStream = ResourceUtils.getInputStreamForPath(configFile);
byte[] b = IOUtils.toByteArray(inputStream);
InputStream in = new ByteArrayInputStream(b);
return in;
}
catch (IOException e)
{
} catch (IOException e) {
throw new ConfigurationException(
"Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e);
}
finally
{
} finally {
IOUtils.closeQuietly(inputStream);
}
}
@ -129,8 +128,7 @@ public class ShiroConfig
* 自定义Realm
*/
@Bean
public UserRealm userRealm(EhCacheManager cacheManager)
{
public UserRealm userRealm(EhCacheManager cacheManager) {
UserRealm userRealm = new UserRealm();
userRealm.setCacheManager(cacheManager);
return userRealm;
@ -140,8 +138,7 @@ public class ShiroConfig
* 自定义sessionDAO会话
*/
@Bean
public OnlineSessionDAO sessionDAO()
{
public OnlineSessionDAO sessionDAO() {
OnlineSessionDAO sessionDAO = new OnlineSessionDAO();
return sessionDAO;
}
@ -150,8 +147,7 @@ public class ShiroConfig
* 自定义sessionFactory会话
*/
@Bean
public OnlineSessionFactory sessionFactory()
{
public OnlineSessionFactory sessionFactory() {
OnlineSessionFactory sessionFactory = new OnlineSessionFactory();
return sessionFactory;
}
@ -160,8 +156,7 @@ public class ShiroConfig
* 会话管理器
*/
@Bean
public OnlineWebSessionManager sessionManager()
{
public OnlineWebSessionManager sessionManager() {
OnlineWebSessionManager manager = new OnlineWebSessionManager();
// 加入缓存管理器
manager.setCacheManager(getEhCacheManager());
@ -186,11 +181,22 @@ public class ShiroConfig
* 安全管理器
*/
@Bean
public SecurityManager securityManager(UserRealm userRealm, SpringSessionValidationScheduler springSessionValidationScheduler)
{
public SecurityManager securityManager(UserRealm userRealm, SpringSessionValidationScheduler springSessionValidationScheduler) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(userRealm);
// securityManager.setRealm(userRealm);
// 修改为多realm
securityManager.setAuthenticator(modularRealmAuthenticator());
List<Realm> realms = new ArrayList<>();
// 统一角色权限控制realm
realms.add(authorizingRealm());
// 用户密码登录realm
realms.add(userRealm());
// 短信登录
realms.add(userPhoneRealm());
securityManager.setRealms(realms);
// 记住我
securityManager.setRememberMeManager(rememberMeManager());
// 注入缓存管理器;
@ -203,8 +209,7 @@ public class ShiroConfig
/**
* 退出过滤器
*/
public LogoutFilter logoutFilter()
{
public LogoutFilter logoutFilter() {
LogoutFilter logoutFilter = new LogoutFilter();
logoutFilter.setLoginUrl(loginUrl);
return logoutFilter;
@ -214,8 +219,7 @@ public class ShiroConfig
* Shiro过滤器配置
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager)
{
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// Shiro的核心安全接口,这个属性是必须的
shiroFilterFactoryBean.setSecurityManager(securityManager);
@ -241,6 +245,8 @@ public class ShiroConfig
filterChainDefinitionMap.put("/logout", "logout");
// 不需要拦截的访问
filterChainDefinitionMap.put("/login", "anon,captchaValidate");
// 不需要拦截的访问
filterChainDefinitionMap.put("/phoneLogin", "anon,captchaValidate");
// 系统权限列表
// filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll());
@ -263,8 +269,7 @@ public class ShiroConfig
* 自定义在线用户处理过滤器
*/
@Bean
public OnlineSessionFilter onlineSessionFilter()
{
public OnlineSessionFilter onlineSessionFilter() {
OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter();
onlineSessionFilter.setLoginUrl(loginUrl);
return onlineSessionFilter;
@ -274,8 +279,7 @@ public class ShiroConfig
* 自定义在线用户同步过滤器
*/
@Bean
public SyncOnlineSessionFilter syncOnlineSessionFilter()
{
public SyncOnlineSessionFilter syncOnlineSessionFilter() {
SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter();
return syncOnlineSessionFilter;
}
@ -284,8 +288,7 @@ public class ShiroConfig
* 自定义验证码过滤器
*/
@Bean
public CaptchaValidateFilter captchaValidateFilter()
{
public CaptchaValidateFilter captchaValidateFilter() {
CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter();
captchaValidateFilter.setCaptchaEnabled(captchaEnabled);
captchaValidateFilter.setCaptchaType(captchaType);
@ -295,8 +298,7 @@ public class ShiroConfig
/**
* cookie 属性设置
*/
public SimpleCookie rememberMeCookie()
{
public SimpleCookie rememberMeCookie() {
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setDomain(domain);
cookie.setPath(path);
@ -308,8 +310,7 @@ public class ShiroConfig
/**
* 记住我
*/
public CookieRememberMeManager rememberMeManager()
{
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ=="));
@ -320,8 +321,7 @@ public class ShiroConfig
* thymeleaf模板引擎和shiro框架的整合
*/
@Bean
public ShiroDialect shiroDialect()
{
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
@ -330,10 +330,57 @@ public class ShiroConfig
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
@Qualifier("securityManager") SecurityManager securityManager)
{
@Qualifier("securityManager") SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 自定义的Realm管理主要针对多realm
*/
@Bean("myModularRealmAuthenticator")
public MyModularRealmAuthenticator modularRealmAuthenticator() {
MyModularRealmAuthenticator customizedModularRealmAuthenticator = new MyModularRealmAuthenticator();
// 设置realm判断条件
customizedModularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
return customizedModularRealmAuthenticator;
}
@Bean
public AuthorizingRealm authorizingRealm() {
AuthorizationRealm authorizationRealm = new AuthorizationRealm();
authorizationRealm.setName(LoginType.COMMON.getType());
return authorizationRealm;
}
/**
* 账号密码登录realm
*
* @return
*/
@Bean
public UserRealm userRealm() {
UserRealm userRealm = new UserRealm();
userRealm.setName(LoginType.USER_PASSWORD.getType());
return userRealm;
}
/**
* 手机号验证码登录realm
*
* @return
*/
@Bean
public UserPhoneRealm userPhoneRealm() {
UserPhoneRealm userPhoneRealm = new UserPhoneRealm();
userPhoneRealm.setName(LoginType.USER_PHONE.getType());
return userPhoneRealm;
}
}

View File

@ -0,0 +1,36 @@
package com.ruoyi.framework.shiro;
/**
* @Description 登录方式的枚举类存放我们所有的登录方式
* https://blog.csdn.net/zhourenfei17/article/details/88826911
* @Author 胡浩
* @Date 2019/6/3
**/
public enum LoginType {
/** 通用 **/
COMMON("common_realm"),
/** 用户密码登录 **/
USER_PASSWORD("user_password_realm"),
/** 手机验证码登录 **/
USER_PHONE("user_phone_realm"),
/** 二维码登录 **/
QRCODE_LOGIN("qrcode_login_realm"),
/** 第三方登录(微信登录) **/
WECHAT_LOGIN("wechat_login_realm");
private String type;
private LoginType(String type) {
this.type = type;
}
public String getType() {
return type;
}
@Override
public String toString() {
return this.type.toString();
}
}

View File

@ -0,0 +1,43 @@
package com.ruoyi.framework.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.realm.Realm;
import java.util.Collection;
import java.util.HashMap;
/**
* @Description
* 创建自定义的多relam的管理策略
* @Author 胡浩
* @Date 2019/6/3
**/
public class MyModularRealmAuthenticator extends ModularRealmAuthenticator {
@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
// 判断getRealms()是否返回为空
assertRealmsConfigured();
// 所有Realm
Collection<Realm> realms = getRealms();
// 登录类型对应的所有Realm
HashMap<String, Realm> realmHashMap = new HashMap<>(realms.size());
for (Realm realm : realms) {
realmHashMap.put(realm.getName(), realm);
}
UserToken token = (UserToken) authenticationToken;
// 登录类型
LoginType loginType = token.getLoginType();
if (realmHashMap.get(loginType.getType()) != null) {
return doSingleRealmAuthentication(realmHashMap.get(loginType.getType()), token);
} else {
return doMultiRealmAuthentication(realms, token);
}
}
}

View File

@ -0,0 +1,55 @@
package com.ruoyi.framework.shiro;
import org.apache.shiro.authc.UsernamePasswordToken;
/**
* @Description
* @Author 胡浩
* @Date 2019/6/3
**/
public class UserToken extends UsernamePasswordToken {
/**
* 登录方式
**/
private LoginType loginType;
/**
* 微信code
**/
private String code;
public UserToken(final String username, final String password, LoginType loginType) {
super(username, password);
this.loginType = loginType;
}
/**
* 记住我
**/
public UserToken(String username, String password, boolean rememberMe, LoginType loginType) {
super(username, password, rememberMe);
this.loginType = loginType;
}
// TODO 由于是demo方法此处微信只传一个code参数其他参数根据实际情况添加
public UserToken(String username, String password, String code, LoginType loginType) {
super(username, password);
this.loginType = loginType;
this.code = code;
}
public LoginType getLoginType() {
return loginType;
}
public void setLoginType(LoginType loginType) {
this.loginType = loginType;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.framework.shiro.realm;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysRoleService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.Set;
/**
* @Description 统一角色授权管理realm
* 当我们往shiro的SecurityManager中注入多个realm后当一个新用户调用需授权的方法时
* 会依次调用所有的realm的doGetAuthoriztionInfo方法
* 而不是根据登录类型来调用不同realm的授权方法因此为了避免重复代码或者说重复授权我们这边做统一处理
* @Author 胡浩
* @Date 2019/6/4
**/
public class AuthorizationRealm extends AuthorizingRealm {
@Autowired
private ISysMenuService menuService;
@Autowired
private ISysRoleService roleService;
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
SysUser user = ShiroUtils.getSysUser();
// 角色列表
Set<String> roles = new HashSet<String>();
// 功能列表
Set<String> menus = new HashSet<String>();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 管理员拥有所有权限
if (user.isAdmin()) {
info.addRole("admin");
info.addStringPermission("*:*:*");
} else {
roles = roleService.selectRoleKeys(user.getUserId());
menus = menuService.selectPermsByUserId(user.getUserId());
// 角色加入AuthorizationInfo认证对象
info.setRoles(roles);
// 权限加入AuthorizationInfo认证对象
info.setStringPermissions(menus);
}
return info;
}
/**
* 清理缓存权限
*/
public void clearCachedAuthorizationInfo() {
this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
/**
* 认证信息.(身份验证) : Authentication 是用来验证用户身份
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
return null;
}
}

View File

@ -0,0 +1,93 @@
package com.ruoyi.framework.shiro.realm;
import com.ruoyi.common.exception.user.*;
import com.ruoyi.framework.shiro.LoginType;
import com.ruoyi.framework.shiro.UserToken;
import com.ruoyi.framework.shiro.service.SysLoginService;
import com.ruoyi.system.domain.SysUser;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @Description
* @Author 胡浩
* @Date 2019/6/4
**/
public class UserPhoneRealm extends AuthorizingRealm {
private static final Logger log = LoggerFactory.getLogger(UserPhoneRealm.class);
@Autowired
private SysLoginService loginService;
@Override
public String getName() {
return LoginType.USER_PHONE.getType();
}
@Override
public boolean supports(AuthenticationToken token) {
if (token instanceof UserToken) {
return ((UserToken) token).getLoginType() == LoginType.USER_PHONE;
} else {
return false;
}
}
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
return null;
}
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UserToken upToken = (UserToken) token;
// UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String phone = upToken.getUsername();
String validCode = "";
if (upToken.getPassword() != null) {
validCode = new String(upToken.getPassword());
}
SysUser user = null;
try {
user = loginService.phoneLogin(phone, validCode);
} catch (CaptchaException e) {
throw new AuthenticationException(e.getMessage(), e);
} catch (UserNotExistsException e) {
throw new UnknownAccountException(e.getMessage(), e);
} catch (UserPasswordNotMatchException e) {
throw new IncorrectCredentialsException(e.getMessage(), e);
} catch (UserPasswordRetryLimitExceedException e) {
throw new ExcessiveAttemptsException(e.getMessage(), e);
} catch (UserBlockedException e) {
throw new LockedAccountException(e.getMessage(), e);
} catch (RoleBlockedException e) {
throw new LockedAccountException(e.getMessage(), e);
} catch (Exception e) {
log.info("对用户[" + phone + "]进行登录验证..验证未通过{}", e.getMessage());
throw new AuthenticationException(e.getMessage(), e);
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, validCode, getName());
return info;
}
/**
* 清理缓存权限
*/
public void clearCachedAuthorizationInfo() {
this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
}

View File

@ -1,44 +1,27 @@
package com.ruoyi.framework.shiro.realm;
import java.util.HashSet;
import java.util.Set;
import com.ruoyi.common.exception.user.*;
import com.ruoyi.framework.shiro.LoginType;
import com.ruoyi.framework.shiro.UserToken;
import com.ruoyi.framework.shiro.service.SysLoginService;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysRoleService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.RoleBlockedException;
import com.ruoyi.common.exception.user.UserBlockedException;
import com.ruoyi.common.exception.user.UserNotExistsException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;
import com.ruoyi.framework.shiro.service.SysLoginService;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysRoleService;
/**
* 自定义Realm 处理登录 权限
*
*
* @author ruoyi
*/
public class UserRealm extends AuthorizingRealm
{
public class UserRealm extends AuthorizingRealm {
private static final Logger log = LoggerFactory.getLogger(UserRealm.class);
@Autowired
@ -50,81 +33,75 @@ public class UserRealm extends AuthorizingRealm
@Autowired
private SysLoginService loginService;
@Override
public String getName() {
return LoginType.USER_PASSWORD.getType();
}
@Override
public boolean supports(AuthenticationToken token) {
if (token instanceof UserToken) {
return ((UserToken) token).getLoginType() == LoginType.USER_PASSWORD;
} else {
return false;
}
}
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0)
{
SysUser user = ShiroUtils.getSysUser();
// 角色列表
Set<String> roles = new HashSet<String>();
// 功能列表
Set<String> menus = new HashSet<String>();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 管理员拥有所有权限
if (user.isAdmin())
{
info.addRole("admin");
info.addStringPermission("*:*:*");
}
else
{
roles = roleService.selectRoleKeys(user.getUserId());
menus = menuService.selectPermsByUserId(user.getUserId());
// 角色加入AuthorizationInfo认证对象
info.setRoles(roles);
// 权限加入AuthorizationInfo认证对象
info.setStringPermissions(menus);
}
return info;
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
// SysUser user = ShiroUtils.getSysUser();
// // 角色列表
// Set<String> roles = new HashSet<String>();
// // 功能列表
// Set<String> menus = new HashSet<String>();
// SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// // 管理员拥有所有权限
// if (user.isAdmin()) {
// info.addRole("admin");
// info.addStringPermission("*:*:*");
// } else {
// roles = roleService.selectRoleKeys(user.getUserId());
// menus = menuService.selectPermsByUserId(user.getUserId());
// // 角色加入AuthorizationInfo认证对象
// info.setRoles(roles);
// // 权限加入AuthorizationInfo认证对象
// info.setStringPermissions(menus);
// }
// return info;
return null;
}
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
String password = "";
if (upToken.getPassword() != null)
{
if (upToken.getPassword() != null) {
password = new String(upToken.getPassword());
}
SysUser user = null;
try
{
try {
user = loginService.login(username, password);
}
catch (CaptchaException e)
{
} catch (CaptchaException e) {
throw new AuthenticationException(e.getMessage(), e);
}
catch (UserNotExistsException e)
{
} catch (UserNotExistsException e) {
throw new UnknownAccountException(e.getMessage(), e);
}
catch (UserPasswordNotMatchException e)
{
} catch (UserPasswordNotMatchException e) {
throw new IncorrectCredentialsException(e.getMessage(), e);
}
catch (UserPasswordRetryLimitExceedException e)
{
} catch (UserPasswordRetryLimitExceedException e) {
throw new ExcessiveAttemptsException(e.getMessage(), e);
}
catch (UserBlockedException e)
{
} catch (UserBlockedException e) {
throw new LockedAccountException(e.getMessage(), e);
}
catch (RoleBlockedException e)
{
} catch (RoleBlockedException e) {
throw new LockedAccountException(e.getMessage(), e);
}
catch (Exception e)
{
} catch (Exception e) {
log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
throw new AuthenticationException(e.getMessage(), e);
}
@ -135,8 +112,7 @@ public class UserRealm extends AuthorizingRealm
/**
* 清理缓存权限
*/
public void clearCachedAuthorizationInfo()
{
public void clearCachedAuthorizationInfo() {
this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
}

View File

@ -21,6 +21,9 @@ import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.service.ISysUserService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 登录校验方法
*
@ -133,4 +136,60 @@ public class SysLoginService
user.setLoginDate(DateUtils.getNowDate());
userService.updateUserInfo(user);
}
/**
* 手机验证码登录
*/
public SysUser phoneLogin(String phone, String validCode) {
//TODO 验证验证码
// // 验证码校验
// if (!StringUtils.isEmpty(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) {
// AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
// throw new CaptchaException();
// }
// 手机或验证码为空 错误
if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(validCode)) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
throw new UserNotExistsException();
}
String regex = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(17[013678])|(18[0,5-9]))\\d{8}$";
if (phone.length() != 11) {
System.out.println("手机号应为11位数");
} else {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(phone);
boolean isMatch = m.matches();
if (isMatch) {
System.out.println("您的手机号" + phone + "是正确格式@——@");
} else {
System.out.println("您的手机号" + phone + "是错误格式!!!");
}
}
// 查询用户信息
SysUser user = userService.selectUserByPhoneNumber(phone);
if (user == null) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists")));
throw new UserNotExistsException();
}
if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.password.delete")));
throw new UserDeleteException();
}
if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.blocked", user.getRemark())));
throw new UserBlockedException();
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
recordLoginInfo(user);
return user;
}
}

View File

@ -1,5 +1,6 @@
package com.ruoyi.framework.util;
import com.ruoyi.framework.shiro.realm.AuthorizationRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.mgt.RealmSecurityManager;
@ -60,7 +61,8 @@ public class ShiroUtils
public static void clearCachedAuthorizationInfo()
{
RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
UserRealm realm = (UserRealm) rsm.getRealms().iterator().next();
// UserRealm realm = (UserRealm) rsm.getRealms().iterator().next();
AuthorizationRealm realm = (AuthorizationRealm) rsm.getRealms().iterator().next();
realm.clearCachedAuthorizationInfo();
}