springboot怎么整合shiro实现多验证登录功能

springboot怎么整合shiro实现多验证登录功能

这篇“springboot怎么整合shiro实现多验证登录功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“springboot怎么整合shiro实现多验证登录功能”文章吧。

1. 首先新建一个shiroConfig shiro的配置类,代码如下:

springboot怎么整合shiro实现多验证登录功能

@ConfigurationpublicclassSpringShiroConfig{/***@paramrealms这儿使用接口集合是为了实现多验证登录时使用的*@return*/@BeanpublicSecurityManagersecurityManager(Collection<Realm>realms){DefaultWebSecurityManagersManager=newDefaultWebSecurityManager();sManager.setRealms(realms);returnsManager;}@BeanpublicShiroFilterFactoryBeanshiroFilterFactory(SecurityManagersecurityManager){ShiroFilterFactoryBeansfBean=newShiroFilterFactoryBean();sfBean.setSecurityManager(securityManager);//如果是匿名访问时,访问了不能访问的资源跳转的位置sfBean.setLoginUrl("/index");//定义map指定请求过滤规则(哪些资源允许匿名访问,哪些必须认证访问)LinkedHashMap<String,String>map=newLinkedHashMap<>();//静态资源允许匿名访问:"anon"静态资源授权时不能写static下面所有的开放,要将static下面的所有文件夹一个一个的开放,templates同理//map的key可以为文件的位置,也可以为请求的路径map.put("/bower_components/**","anon");map.put("/json/**","anon");map.put("/pages","anon");map.put("/user/userPasswordLogin","anon");map.put("/user/login","anon");map.put("/user/reg","anon");//访问这个路径时不会进入controller,会在这儿直接拦截退出,问为什么的,自己想请求流程去map.put("/user/userLogout","logout");//拦截除上面之外的所有请求路径map.put("/**","user");sfBean.setFilterChainDefinitionMap(map);returnsfBean;}@BeanpublicLifecycleBeanPostProcessorlifecycleBeanPostProcessor(){returnnewLifecycleBeanPostProcessor();}

2. 写Realms的实现类,一般继承自AuthorizingRealm(这个是实现用户名,密码登录),代码如下:

@ServicepublicclassShioUserRealmextendsAuthorizingRealm{//注入userdao@AutowiredprivateUserDaouserDao;/***设置凭证匹配器**@paramcredentialsMatcher*/@OverridepublicvoidsetCredentialsMatcher(CredentialsMatchercredentialsMatcher){/*这里设置了MD5盐值加密,这儿就必须使用HashedCredentialsMatcher才能有下面两个方法*/HashedCredentialsMatchermatcher=newHashedCredentialsMatcher();//这里是设置加密方式matcher.setHashAlgorithmName("MD5");//这里是设置加密的次数matcher.setHashIterations(2);super.setCredentialsMatcher(matcher);}/***这儿是设置授权的*@paramprincipalCollection*@return*/@OverrideprotectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipalCollection){returnnull;}/***通过此方法完成认证数据的获取及封装,系统底层会将认证数据传递认证管理器,有认证管理器完成认证操作*@paramauthenticationToken*@return*@throwsAuthenticationException*/@OverrideprotectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthenticationToken)throwsAuthenticationException{//先判断这个是否是来及这个令牌的数据:我们这儿分为了UsernamePasswordToken(shiro给我们提供的。)、UserPhoneTokenif(!(authenticationTokeninstanceofUsernamePasswordToken)){returnnull;}//获取controller传过来的数据UsernamePasswordTokenupToken=(UsernamePasswordToken)authenticationToken;//upToken.setRememberMe(true);shiro默认为false,是是否记住我的功能//这儿为用户提交的usernameStringusername=upToken.getUsername();//去数据更加name取到用户的信息Useruser=userDao.findUserByUserName(username);//判断数据库是否有这用户if(user==null){thrownewUnknownAccountException();}//判断用户的状态是否被禁用(数据库的字段)if(user.getState()==0){thrownewLockedAccountException();}//这儿是取到用户信息中的盐值,盐值要转换为ByteSource这个类型才能使用ByteSourcecredentialsSalt=ByteSource.Util.bytes(user.getSalt());//这儿是将这个用户的信息交给shiro(user为用户对象,user.getPassword()是要加密的对象,credentialsSalt为盐值,getName()当前对象)SimpleAuthenticationInfoinfo=newSimpleAuthenticationInfo(user,user.getPassword(),credentialsSalt,getName());returninfo;}}

3. 此时用户的账号密码登录已经可以使用了controller代码如下:

@RequestMapping("userPasswordLogin")@ResponseBodypublicJsonResultuserPasswordLogin(Stringusername,Stringpassword){Subjectsubject=SecurityUtils.getSubject();UsernamePasswordTokentoken=newUsernamePasswordToken(username,password);subject.login(token);returnnewJsonResult("loginOk");}

4. 我们现在来实现短信验证码登录实现:

4.1 先写UserPhoneToken,我放在l和springShiroConfig同一目录下:

@ComponentpublicclassUserPhoneTokenextendsUsernamePasswordTokenimplementsSerializable{privatestaticfinallongserialVersionUID=6293390033867929958L;//手机号码privateStringphoneNum;//无参构造publicUserPhoneToken(){}//获取存入的值@OverridepublicObjectgetPrincipal(){if(phoneNum==null){returngetUsername();}else{returngetPhoneNum();}}@OverridepublicObjectgetCredentials(){if(phoneNum==null){returngetPassword();}else{return"ok";}}publicUserPhoneToken(StringphoneNum){this.phoneNum=phoneNum;}publicUserPhoneToken(finalStringuserName,finalStringpassword){super(userName,password);}publicStringgetPhoneNum(){returnphoneNum;}publicvoidsetPhoneNum(StringphoneNum){this.phoneNum=phoneNum;}@OverridepublicStringtoString(){return"PhoneToken[PhoneNum="+phoneNum+"]";}}

4.2 在写shiroUserPhoneRealm,代码如下:

@ServicepublicclassShioUserPhoneRealmextendsAuthorizingRealm{@AutowiredprivateUserDaouserDao;@OverridepublicvoidsetCredentialsMatcher(CredentialsMatchercredentialsMatcher){//这儿的CredentialsMatcher的new的对象必须是AllowAllCredentialsMatcherCredentialsMatchermatcher=newAllowAllCredentialsMatcher();super.setCredentialsMatcher(matcher);}@OverrideprotectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipalCollection){returnnull;}/***通过此方法完成认证数据的获取及封装,系统底层会将认证数据传递认证管理器,有认证管理器完成认证操作*@paramauthenticationToken*@return*@throwsAuthenticationException*/@OverrideprotectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthenticationToken)throwsAuthenticationException{UserPhoneTokentoken=null;if(authenticationTokeninstanceofUserPhoneToken){token=(UserPhoneToken)authenticationToken;}else{returnnull;}//获取我发送验证码是存入session中的验证码和手机号StringverificationCode=(String)SecurityUtils.getSubject().getSession().getAttribute("verificationCode");Stringphone=(String)SecurityUtils.getSubject().getSession().getAttribute("phone");//获取controller传过来的数据StringverificationCode1=(String)token.getPrincipal();//去数据库根据手机号查询用户信息Useruser=userDao.findUserByUserPhone(phone);if(StringUtils.isEmpty(verificationCode)){thrownewServiceException("网络错误");}//比对手机号if(!verificationCode.equals(verificationCode1)){thrownewServiceException("验证码不正确");}if(user==null){thrownewUnknownAccountException();}if(user.getState()==0){thrownewLockedAccountException();}returnnewSimpleAuthenticationInfo(user,phone,getName());}}

4.3 手机号码登录验证已经基本完成:controller代码如下:

@PostMapping("verificationCodeLogin")@ResponseBodypublicJsonResultverificationCodeLogin(Stringpassword){Subjectsubject=SecurityUtils.getSubject();UserPhoneTokentoken=newUserPhoneToken(password);subject.login(token);returnnewJsonResult("loginOK");}

使用过程中遇到的bug

1.

org.apache.shiro.authc.UnknownAccountException: Realm [cn.tedu.wxacs.service.impl.ShioUserPhoneRealm@768d8431] was unable to find account data for the submitted AuthenticationToken [org.apache.shiro.authc.UsernamePasswordToken - 张三, rememberMe=false].

出现这个问题是我的是因为Realm中的某个实现类没有加注解,我这儿演示时是应为ShiroUserRealm为加@Service注解

2.

org.apache.shiro.authc.AuthenticationException: Authentication token of type [class org.apache.shiro.authc.UsernamePasswordToken] could not be authenticated by any configured realms. Please ensure that at least one realm can authenticate these tokens.

这儿出现的问题是应为我的ShioUserRealm的AuthenticationInfo方法的User user = userDao.findUserByUserName(username);这行代码出现的问题,debug的时候就发现这一句执行后就保错

原因:是因为我的application.yml文件中没有写dao对应的mapper文件的路径

3. 在ShioUserPhoneRealm的doGetAuthenticationInfo方法的new SimpleAuthenticationInfo(user,phone,getName())这个位置后就报错是应为ShioUserPhoneRealm的这个方法中你没有将new的对象设置为AllowAllCredentialsMatcher();

@OverridepublicvoidsetCredentialsMatcher(CredentialsMatchercredentialsMatcher){//这儿的CredentialsMatcher的new的对象必须是AllowAllCredentialsMatcherCredentialsMatchermatcher=newAllowAllCredentialsMatcher();super.setCredentialsMatcher(matcher);}

以上就是关于“springboot怎么整合shiro实现多验证登录功能”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注恰卡编程网行业资讯频道。

发布于 2022-04-03 22:32:48
收藏
分享
海报
0 条评论
22
上一篇:SpringBoot怎么集成EasyExcel应用 下一篇:SpringBoot拦截器源码分析
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码