SpringBoot shiro多realm配置认证授权,直接运行版本
技术:springboot+shiro+thymeleaf+html+jquery+mevan
概述
场景介绍 Springboot shiro 用户名密码或手机号短信登录 (多realm配置认证、授权) ,用于web网站。选择用户名或者手机号登录后,系统认证授权。
详细
功能演示
一、目录结构
二、功能讲解
(1)ShiroConfig 配置类
/** * shiro配置类 */ @Configuration public class ShiroConfig { @Bean("shiroFilterFactoryBean") ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/index", "authc"); filterChainDefinitionMap.put("/static/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(UsernamePasswordRealm usernamePasswordRealm, MobileRealm mobileRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setAuthenticator(modularRealmAuthenticator()); // 设置realms List<Realm> realms = new ArrayList<Realm>(); realms.add(usernamePasswordRealm); realms.add(mobileRealm); securityManager.setRealms(realms); return securityManager; } //重要!!定义token与Realm关系,设置认证策略 @Bean public ModularRealmAuthenticator modularRealmAuthenticator(){ MyModularRealmAuthenticator authenticator = new MyModularRealmAuthenticator(); FirstSuccessfulStrategy firstSuccessfulStrategy = new FirstSuccessfulStrategy(); authenticator.setAuthenticationStrategy(firstSuccessfulStrategy); return authenticator; } @Bean MobileRealm mobileRealm() { MobileRealm mobileRealm = new MobileRealm(); return mobileRealm; } @Bean @DependsOn({"hashedCredentialsMatcher"}) UsernamePasswordRealm usernamePasswordRealm(HashedCredentialsMatcher matcher) { UsernamePasswordRealm usernamePasswordRealm = new UsernamePasswordRealm(); usernamePasswordRealm.setCredentialsMatcher(matcher); return usernamePasswordRealm; } public static final String hashAlgorithName = "md5"; public static final Integer hashIterations = 1024; @Bean(name = "hashedCredentialsMatcher") public HashedCredentialsMatcher hashedCredentialsMatcher(){ HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName(hashAlgorithName);//散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashIterations(hashIterations);//散列的次数,比如散列两次,相当于 md5(md5("")); return hashedCredentialsMatcher; } }
(2)MobileRealm 手机认证授权类
/** * 手机认证授权类 * @author juno * @date 2020/03/03 */ public class MobileRealm extends AuthorizingRealm { @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("授权逻辑-->MobileRealm.doGetAuthorizationInfo()"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 省略 return info; } /** * 主要是用来进行身份认证的,也就是说验证用户输入的手机号码是否正确。 * @param authcToken * @return AuthenticationInfo * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { System.out.println("Realm : " + this.getName()); MobileToken mobileToken = null; if(authcToken instanceof MobileToken){ mobileToken = (MobileToken) authcToken; }else{ return null; } //例子1,模拟手机 String mobile = mobileToken.getMobile(); //模拟实体类 Member member = new Member(); member.setId(20L); member.setMobile(mobile); member.setLoginType(Member.LOGIN_TYPE_MOBILE); AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(member, mobile, this.getName()); //清之前的授权信息 super.clearCachedAuthorizationInfo(authcInfo.getPrincipals()); SecurityUtils.getSubject().getSession().setAttribute("member", member); return authcInfo; // 例子2,走数据库判断 //通过mobile从数据库中查找 Member对象 // Member member = this.memberService.findMemberByMobile(mobile); // if(member == null){ // throw new UnknownAccountException(); // } // //手机-被禁止登录 // if(StringUtils.equals(member.getStatus(),Member.STATUS_INACTIVE)){ // throw new DisabledAccountException(); // } // AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(member, mobile, this.getName()); // //清之前的授权信息 // super.clearCachedAuthorizationInfo(authcInfo.getPrincipals()); // SecurityUtils.getSubject().getSession().setAttribute("member", member); // return authcInfo; } @Override public boolean supports(AuthenticationToken authenticationToken){ return authenticationToken != null && (authenticationToken instanceof MobileToken ); } }
(3)UsernamePasswordRealm 用户名密码认证授权类
/** * 用户名密码认证授权类 * @author juno * @date 2020/02/28 */ public class UsernamePasswordRealm extends AuthorizingRealm { public static final String CREDENTIALS_SALT = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("授权逻辑-->UsernamePasswordRealm.doGetAuthorizationInfo()"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 省略 return info; } /** * 主要是用来进行身份认证的,也就是说验证用户输入的用户名和密码是否正确。 * @param authcToken * @return AuthenticationInfo * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { System.out.println("Realm : " + this.getName()); UsernamePasswordToken usernamePasswordToken = null; if(authcToken instanceof UsernamePasswordToken){ usernamePasswordToken = (UsernamePasswordToken) authcToken; }else{ return null; } String username = usernamePasswordToken.getUsername(); String password = new String((char[]) usernamePasswordToken.getPassword()); //例子1,模拟用户名 if(!StringUtils.equals(username,"test")){ //用户名不存在 throw new UnknownAccountException(); } String HASH_ALGORITH_NAME = "md5"; Integer HASH_ITERATIONS = 1024; //加密后的密码 String encryptionPassword = new SimpleHash(HASH_ALGORITH_NAME, password, ByteSource.Util.bytes(CREDENTIALS_SALT) , HASH_ITERATIONS).toString(); //模拟实体类 Member member = new Member(); member.setId(100L); member.setUsername(username); member.setLoginPassword(encryptionPassword); member.setLoginType(Member.LOGIN_TYPE_LOGINNAME); AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(member, member.getLoginPassword(), ByteSource.Util.bytes(CREDENTIALS_SALT), this.getName()); //清之前的授权信息 super.clearCachedAuthorizationInfo(authcInfo.getPrincipals()); SecurityUtils.getSubject().getSession().setAttribute("member", member); return authcInfo; // 例子2,走数据库判断 //通过username从数据库中查找 Member对象 // Member member = this.memberDao.findMemberByUsername(username); // //用户名不存在 // if(member == null){ // throw new UnknownAccountException(); // }else{ // String HASH_ALGORITH_NAME = "md5"; // Integer HASH_ITERATIONS = 1024; // String encryptionPassword = new SimpleHash(HASH_ALGORITH_NAME, password, ByteSource.Util.bytes(CREDENTIALS_SALT) , HASH_ITERATIONS).toString(); // //判断密码是否正确 // if(!StringUtils.equals(member.getLoginPassword(),encryptionPassword)){ // throw new IncorrectCredentialsException(); // } // // } // //用户名被禁止登录 // if(StringUtils.equals(member.getStatus(),Member.STATUS_INACTIVE)){ // throw new DisabledAccountException(); // } // AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(member, member.getLoginPassword(), ByteSource.Util.bytes(credentialsSalt), this.getName()); // //清之前的授权信息 // super.clearCachedAuthorizationInfo(authcInfo.getPrincipals()); // SecurityUtils.getSubject().getSession().setAttribute("member", member); // return authcInfo; } @Override public boolean supports(AuthenticationToken authenticationToken){ return authenticationToken != null && (authenticationToken instanceof UsernamePasswordToken); } }
(3)MemberController 会员控制类
/** * 会员控制类 */ @Controller public class MemberController { @Resource private MemberService memberService; /** * 登录页 */ @GetMapping(value = {"/", "/login"}) public String login() { return "/login"; } /** * 主页 */ @GetMapping(value = {"/index"}) public String index() { return "/index"; } /** * 用户名登录 */ @RequestMapping("/usernameLogin") @ResponseBody public Message authLogin(HttpServletRequest request) throws Exception { HashMap<String, Object> paramMap = CommonUtil.checkRequestParam(request, new String[]{"username", "password"}); return this.memberService.usernameLogin(paramMap.get("username").toString(), paramMap.get("password").toString()); } /** * 手机登录 */ @RequestMapping("/mobileLogin") @ResponseBody public Message mobileLogin(HttpServletRequest request) throws Exception { HashMap<String, Object> paramMap = CommonUtil.checkRequestParam(request, new String[]{"mobile", "smsValidateCode"}); return this.memberService.mobileLogin(paramMap.get("mobile").toString(), paramMap.get("smsValidateCode").toString()); } }
三、前端页面
(1)login.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>登录页</title> </head> <link rel="stylesheet" href="/css/login.css"> <script src="/js/jquery-1.12.4.min.js"></script> <script src="/js/ajax.js"></script> <script src="/js/login.js"></script> <body> <h1> 登录页</h1> <!--header begin--> <div class="header"> <div class="container cl"> <h1 class="site-logo"> <div></div> </h1> </div> </div> <!--header end--> <div class="login"> <div class="login-bg"></div> <div class="container"> <div class="login-box"> <ul class="cl" id="tab"> <li class="active"><a href="javascript: void(0);">手机登录</a></li> <li><a href="javascript: void(0);">用户名登录</a></li> </ul> <div class="panel" id="panel"> <div style="display: block;"> <form action="" class="login-form quick-login"> <div class="item"> <input class="input-txt" id="mobile" type="text" name="mobile" placeholder="手机号码" value="13318816600" /> <div class="error-message"></div> </div> <div class="item"> <div class="input"> <input class="input-txt" id="smsValidateCode" type="text" name="smsValidateCode" placeholder="动态密码" value="8461"/> <div class="cover"> <a style="cursor: pointer" href="javascript: void(0);">获取动态密码</a> </div> </div> <div class="error-message"></div> </div> <div class="item"> <button id="mobileLoginButton" type="button" class="btn" onclick="mobileLogin()">登录</button> </div> </form> </div> <div> <form action="" class="login-form quick-login"> <div class="item"> <input class="input-txt" type="text" name="username" id="username" placeholder="用户名" value="test"/> <div class="error-message"></div> </div> <div class="item"> <input class="input-txt" type="password" name="password" id="password" placeholder="请输入密码" value="1111"/> <div class="error-message"></div> </div> <div class="item"> <div class="error-message"></div> </div> <div class="item cl"> <div class="fl"> <input type="checkbox" title="" class="checkbox"/>记住密码 </div> <div class="fr"> <a href="">忘记密码?</a> </div> </div> <div class="item"> <button id="usernameLoginButton" type="button" class="btn" onclick="usernameLogin();">登录</button> </div> </form> </div> </div> <div class="toolbar cl"> <div class="fr"> <a href="javascript: void(0);" class="register-btn">立即注册</a> </div> </div> </div> </div> </div> </body> </html>
(2)index.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>index 页</title> </head> <body> <h1>index页</h1> <div th:if="${session.member.loginType == '0'}"> <h3>用户名: <span th:text="${session.member.username}"></span> </h3> </div> <span th:if="${session.member.loginType == '1'}"> <h3>手机号码: <span th:if="${session.member.loginType == '1'}" th:text="${session.member.mobile}"></span> </h3> </span> <span> </span> <span> </span> <span> </span> <div> <a style="font-size: 20px;color: red;" href="/logout">登出</a> </div> </body> </html>
四、运行
http://127.0.0.1:8080/index 首页(需要鉴权才能进入)
手机登录:
用户名登录:
谢谢大家观看~
联系方式
QQ:359355126 蓝蓝的天
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码