若依免密登录
???????????最近做了一個微信掃碼登錄的功能整合到若依中,當掃碼完成后,如何確定是哪個用戶,以及權限有哪些,因為shiro的加密基于MD5所以密碼不可逆,則不能從數據庫查詢后再解密,簡單一些的話可以把需要登錄的用戶賬號密碼寫死在配置文件中,我之前就是這么干的,但是這樣做的話一旦修改密碼,則需要修改配置文件,所以我想到了免密登錄,在網上查了好多shiro的改造,也沒整明白怎么回事,繼承的類也是不知道干嘛的,所以自己研究了一下若依的實現過程,終于實現了可免密登錄
第一步:如果需要免密登錄就需要有個標志來確定是不是從微信掃碼過來的,不然賬號密碼登錄就不用輸入密碼也能進來,這顯然是不對的
創建一個枚舉,來當做標志
package com.clpc.un.framework.shiro.wxconfig;public enum LoginType {PASSWORD("password"),NOPASSWORD("nopassword");private String code;LoginType(String code) {this.code = code;}public String getCode() {return code;}}第二步:我的業務是根據部門確定是哪個用戶,寫的比較low,還沒做優化,在拿到部門id后就要進行登錄,執行若依中原來的登錄方法(改造過)
public void execLogin(HttpServletRequest request,String deptId){log.info("登錄用戶部門Id:" + deptId);String loginName;//登錄用戶名if(deptId.equals("3") || deptId.equals("1190")){loginName = "admin";} else {loginName = "ChinaLife";}//執行免密登錄loginController.ajaxLogin(request,loginName,"",true);}第三步:上一步的登錄方法我是進行了改造,根據request獲取訪問過來的路徑,由此判斷是微信,還是賬號密碼,這里面的token也是改造過的,生成token時把登錄類型帶上,就是我們寫的token
@PostMapping("/login")@ResponseBodypublic AjaxResult ajaxLogin(HttpServletRequest request,String username, String password, Boolean rememberMe){//UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);//根據地址判斷是否是微信登錄WxLoginToken token = null;if(request.getServletPath().equals("/weChat/wechatLogin")){token = new WxLoginToken(username, password, rememberMe, LoginType.NOPASSWORD);} else {token = new WxLoginToken(username, password, rememberMe, LoginType.PASSWORD);}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);}}第四部:修改UsernameAndPasswordToken,繼承后修改即可,大部分都是繼承過來的,只有一個登錄方法,和變量type是自己寫的,目的是在token中攜帶登錄類型
package com.clpc.un.framework.shiro.wxconfig;import org.apache.shiro.authc.UsernamePasswordToken;public class WxLoginToken extends UsernamePasswordToken {private LoginType type;public WxLoginToken() {super();}public WxLoginToken(String username, char[] password) {super(username, password);}public WxLoginToken(String username, String password) {super(username, password);}public WxLoginToken(String username, char[] password, String host) {super(username, password, host);}public WxLoginToken(String username, String password, String host) {super(username, password, host);}public WxLoginToken(String username, char[] password, boolean rememberMe) {super(username, password, rememberMe);}public WxLoginToken(String username, String password, boolean rememberMe,LoginType type) {super(username, password, rememberMe);this.type = type;}public WxLoginToken(String username, char[] password, boolean rememberMe, String host) {super(username, password, rememberMe, host);}public WxLoginToken(String username, String password, boolean rememberMe, String host) {super(username, password, rememberMe);}@Overridepublic String getUsername() {return super.getUsername();}@Overridepublic void setUsername(String username) {super.setUsername(username);}@Overridepublic char[] getPassword() {return super.getPassword();}@Overridepublic void setPassword(char[] password) {super.setPassword(password);}@Overridepublic Object getPrincipal() {return super.getPrincipal();}@Overridepublic Object getCredentials() {return super.getCredentials();}@Overridepublic String getHost() {return super.getHost();}@Overridepublic void setHost(String host) {super.setHost(host);}@Overridepublic boolean isRememberMe() {return super.isRememberMe();}@Overridepublic void setRememberMe(boolean rememberMe) {super.setRememberMe(rememberMe);}@Overridepublic void clear() {super.clear();}@Overridepublic String toString() {return super.toString();}public LoginType getType() {return type;}public void setType(LoginType type) {this.type = type;} }第五步:修改Realm,生成的token會傳遞給userRealm,所以這里面肯定是要修改的,把原來的token換成我們自己的token,并修改LoginService.login()方法
/*** 登錄認證*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException{//UsernamePasswordToken upToken = (UsernamePasswordToken) token;//拿到token,此時token中存在登錄類型,即是微信登錄還是賬號密碼登錄WxLoginToken upToken = (WxLoginToken) token;String username = upToken.getUsername();String password = "";if (upToken.getPassword() != null){password = new String(upToken.getPassword());}User user = null;try{user = wxLoginService.login(username, password,upToken.getType());}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("對用戶[" + username + "]進行登錄驗證..驗證未通過{}", e.getMessage());throw new AuthenticationException(e.getMessage(), e);}SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());return info;}第六步:修改LoginService,直接繼承過來修改,盡量不改源文件,如果是通過賬號密碼登錄則正常走原來的流程,驗證密碼之類的,如果來源于微信登錄則直接去查數據庫,不驗證密碼,直接返回查到的user
package com.clpc.un.framework.shiro.wxconfig;import com.clpc.un.common.constant.Constants; import com.clpc.un.common.exception.user.UserNotExistsException; import com.clpc.un.common.utils.MessageUtils; import com.clpc.un.framework.manager.AsyncManager; import com.clpc.un.framework.manager.factory.AsyncFactory; import com.clpc.un.framework.shiro.service.LoginService; import com.clpc.un.project.system.user.domain.User; import com.clpc.un.project.system.user.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;@Service public class WxLoginService extends LoginService {@Autowiredprivate IUserService userService;@Overridepublic User login(String username, String password,LoginType type) {if ( type == LoginType.PASSWORD ){return super.login( username, password, type );} else {User user = userService.selectUserByLoginName(username);if (user == null){AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists")));throw new UserNotExistsException();}recordLoginInfo(user);return user;}}@Overridepublic void recordLoginInfo(User user) {super.recordLoginInfo(user);}}到此為止,免密登錄就完成了,且不影響原有的密碼登錄,即使修改了密碼也不影響我們微信登錄,
此文作為自己的筆記,也給大家做個參考
文章手打不易,希望大家喜歡,多多支持,
總結
- 上一篇: Java 插入排序
- 下一篇: 2022年上半年全球知名企业十大数据泄露