web项目中用户登录的具体流程
一个登录的具体流程:
1、前端发送公钥的请求。
2、后台生产公钥私钥对,将公钥返回前端,私钥保存到session中。
3、前端拿到公钥后,对用户输入的密码进行md5加密,然后在对(md5加密后的密码+密码)进行rsa加密,发起登录请求,将用户名和加密后的密码传入后台进行校验。
4、后台接受到加密后的密码首先利用私钥对密码进行解密
5、对密码进行完整的校验即采用前32位的MD5码与原始密码(32位之后的值即为密码)进行MD5加密后进行比较。
6、验证通过后采用shiro的subject.login()将登陆验证的工作转交给shiro进行。
7、通过判断shiro返回的异常信息来获取校验未成功的原因。
8、验证通过检查此用户在其他地方时候登陆。方法为自定义一个session的缓存将登录过的session与用户名存入map中,从缓存中获取此用户名对应的缓存判断sessionid是否一致,若不一致说明此次是重复登录,将之前的session通过shiroSessionManager.getSessionDAO().delete(session)进行剔除。
9、返回登录结果到前端。
具体代码片段如下:
登录校验:
1 public Result checkLogin(String username, String encryptPassword, RSAPrivateKey privateKey){ 2 3 String decryptPassword = ""; 4 if (privateKey != null && encryptPassword != null) { 5 //解密后的密码。由mds(pass) + pass 组成。 6 decryptPassword = RSAUtils.decrypt(privateKey, encryptPassword); 7 } 8 if(decryptPassword.length() < 32){ 9 return Result.error("用户名或密码验证失败。"); 10 } 11 //完整性校验,防止篡改 12 if (!isComplate(decryptPassword)) { 13 return Result.error("密码被篡改,验证失败。"); 14 } 15 decryptPassword = decryptPassword.substring(32); 16 String password = new Sha256Hash(decryptPassword).toHex(); 17 18 //密码完整性校验通过,交给shiro进行验证 19 //进行验证,这里可以捕获异常,然后返回对应信息 20 try{ 21 Subject subject = SecurityUtils.getSubject(); 22 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password); 23 subject.login(usernamePasswordToken); 24 //剔除重复登录的用户 25 SessionsSecurityManager securityManager = (SessionsSecurityManager) SecurityUtils.getSecurityManager(); 26 DefaultSessionManager shiroSessionManager = (DefaultSessionManager) securityManager.getSessionManager(); 27 Session session = sessionManager.getSession(username); 28 if(session != null){ 29 //不是同一个会话,进行剔除 30 if(!subject.getSession().getId().equals(session.getId())){ 31 shiroSessionManager.getSessionDAO().delete(session); 32 sessionManager.removeSession(username);//缓存中移除 33 } 34 } 35 //将新的用户和session加入sessionManager中 36 sessionManager.addSession(username, subject.getSession()); 37 38 }catch(IncorrectCredentialsException ice){ 39 return Result.error("用户名或密码验证失败"); 40 }catch(UnknownAccountException uae){ 41 return Result.error("账号不存在"); 42 }catch(LockedAccountException uae){ 43 return Result.error("账号被锁定"); 44 }catch(ExcessiveAttemptsException uae){ 45 return Result.error("操作频繁,请稍后再试"); 46 }catch(ExpiredCredentialsException ece){ 47 return Result.error("账号已过期,请重新登录"); 48 } 49 return Result.ok(); 50 }
UserManager
@Component public class UserManager { @Autowired IFetchUser query; private ConcurrentMap<String, User> map = new ConcurrentHashMap<String, User>(); public User getUser(String name){ User user = map.get(name); if(user == null){ //去库中查询 user = query.queryFromDb(name); if(user != null){ map.put(name, user); } } return user; } public void removeUser(String name){ map.remove(name); } }
Shiro的配置
@Configuration public class SysShiroConfiguration { @Bean public MemorySessionDAO memorySessionDAO(){ MemorySessionDAO memorySessionDAO = new MemorySessionDAO(); return memorySessionDAO; } @Bean public WebSessionManager webSessionManager(){ DefaultWebSessionManager webSessionManager = new DefaultWebSessionManager(); webSessionManager.setSessionDAO(memorySessionDAO()); return webSessionManager; } @Bean public MemoryConstrainedCacheManager memoryConstrainedCacheManager(){ MemoryConstrainedCacheManager cacheManager = new MemoryConstrainedCacheManager(); return cacheManager; } //将自己的验证方式加入容器 @Bean public CustomShiroRealm customShiroRealm() { CustomShiroRealm customShiroRealm = new CustomShiroRealm(); return customShiroRealm; } //权限管理,配置主要是Realm的管理认证 @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(customShiroRealm()); securityManager.setCacheManager(memoryConstrainedCacheManager()); securityManager.setSessionManager(webSessionManager()); return securityManager; } //Filter工厂,设置对应的过滤条件和跳转条件 @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String,String> map = new HashMap<String, String>(); //登出 // map.put("/logout","logout"); // map.put("/test/**","anon"); // map.put("/pages/index.jsp","anon"); // map.put("/index.jsp","anon"); // map.put("/statics/**","anon"); //对所有用户认证 map.put("/**","anon"); //登录 shiroFilterFactoryBean.setLoginUrl("/login"); //首页 shiroFilterFactoryBean.setSuccessUrl("/home"); //错误页面,认证不通过跳转 shiroFilterFactoryBean.setUnauthorizedUrl("/error"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){ return new LifecycleBeanPostProcessor(); } @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } //加入注解的使用,不加入这个注解不生效 @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }