shiro多验证登录代码实例及问题解决

这篇文章主要介绍了shiro多验证登录代码实例及问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

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

@Configuration是标识这个类是一个配置文件,在启动时会加载这个类里面的内容,这个配置文件的位置的一定一定一定不能防止启动类外面的文件夹中,否则还会在启动类上加注解

@Bean是将这个类交给spring管理

@Configuration
public class SpringShiroConfig {

  /**
   * @param realms 这儿使用接口集合是为了实现多验证登录时使用的
   * @return
   */
  @Bean
  public SecurityManager securityManager(Collection<Realm> realms) {
    DefaultWebSecurityManager sManager = new DefaultWebSecurityManager();
    sManager.setRealms(realms);
    return sManager;
  }

  @Bean
  public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager) {
    ShiroFilterFactoryBean sfBean = new ShiroFilterFactoryBean();
    sfBean.setSecurityManager(securityManager);
    //如果是匿名访问时,访问了不能访问的资源跳转的位置
    sfBean.setLoginUrl("/index");
    //定义map指定请求过滤规则(哪些资源允许匿名访问,哪些必须认证访问)
    LinkedHashMap<String, String> map = new LinkedHashMap<>();
    //静态资源允许匿名访问:"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);
    return sfBean;
  }

  @Bean
  public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
    return new LifecycleBeanPostProcessor();
  }

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

@Service
public class ShioUserRealm extends AuthorizingRealm {

  //注入userdao
  @Autowired
  private UserDao userDao;
  /**
   * 设置凭证匹配器
   *
   * @param credentialsMatcher
   */
  @Override
  public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
    /*这里设置了MD5盐值加密,这儿就必须使用HashedCredentialsMatcher才能有下面两个方法*/
    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
    //这里是设置加密方式
    matcher.setHashAlgorithmName("MD5");
    //这里是设置加密的次数
    matcher.setHashIterations(2);
    super.setCredentialsMatcher(matcher);
  }

  /**
   * 这儿是设置授权的
   * @param principalCollection
   * @return
   */
  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

    return null;
  }

  /**
   * 通过此方法完成认证数据的获取及封装,系统底层会将认证数据传递认证管理器,有认证管理器完成认证操作
   * @param authenticationToken
   * @return
   * @throws AuthenticationException
   */
  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

    //先判断这个是否是来及这个令牌的数据:我们这儿分为了UsernamePasswordToken(shiro给我们提供的。)、UserPhoneToken
    if (!(authenticationToken instanceof UsernamePasswordToken)) {
      return null;
    }
    //获取controller传过来的数据
    UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;
    //upToken.setRememberMe(true);shiro默认为false,是是否记住我的功能
    //这儿为用户提交的username
    String username = upToken.getUsername();
    //去数据更加name取到用户的信息
    User user = userDao.findUserByUserName(username);
    //判断数据库是否有这用户
    if (user == null) {
      throw new UnknownAccountException();
    }
    //判断用户的状态是否被禁用(数据库的字段)
    if (user.getState() == 0) {
      throw new LockedAccountException();
    }
    //这儿是取到用户信息中的盐值,盐值要转换为ByteSource这个类型才能使用
    ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());
    //这儿是将这个用户的信息交给shiro(user为用户对象,user.getPassword()是要加密的对象,credentialsSalt为盐值,getName()当前对象)
    SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), credentialsSalt, getName());
    return info;
  }
}

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

@RequestMapping("userPasswordLogin")
  @ResponseBody
  public JsonResult userPasswordLogin(String username, String password) {
    Subject subject = SecurityUtils.getSubject();
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    subject.login(token);
    return new JsonResult("login Ok");
  }

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

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

@Component
public class UserPhoneToken extends UsernamePasswordToken implements Serializable {

  private static final long serialVersionUID = 6293390033867929958L;
  // 手机号码
  private String phoneNum;
  //无参构造
  public UserPhoneToken(){}

  //获取存入的值
  @Override
  public Object getPrincipal() {
    if (phoneNum == null) {
      return getUsername();
    } else {
      return getPhoneNum();
    }
  }

  @Override
  public Object getCredentials() {
    if (phoneNum == null) {
      return getPassword();
    }else {
      return "ok";
    }

  }

  public UserPhoneToken(String phoneNum) {
    this.phoneNum = phoneNum;
  }

  public UserPhoneToken(final String userName, final String password) {
    super(userName, password);
  }

  public String getPhoneNum() {
    return phoneNum;
  }

  public void setPhoneNum(String phoneNum) {
    this.phoneNum = phoneNum;
  }
  @Override
  public String toString() {
    return "PhoneToken [PhoneNum=" + phoneNum + "]";
  }

}

4.2 在写shiroUserPhoneRealm,代码如下:

@Service
public class ShioUserPhoneRealm extends AuthorizingRealm {

  @Autowired
  private UserDao userDao;

  @Override
  public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
    //这儿的CredentialsMatcher的new的对象必须是AllowAllCredentialsMatcher
    CredentialsMatcher matcher = new AllowAllCredentialsMatcher();
    super.setCredentialsMatcher(matcher);
  }

  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    return null;
  }

  /**
   * 通过此方法完成认证数据的获取及封装,系统底层会将认证数据传递认证管理器,有认证管理器完成认证操作
   * @param authenticationToken
   * @return
   * @throws AuthenticationException
   */
  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

    UserPhoneToken token = null;
    if (authenticationToken instanceof UserPhoneToken) {
      token = (UserPhoneToken) authenticationToken;
    }else {
      return null;
    }
    //获取我发送验证码是存入session中的验证码和手机号
    String verificationCode = (String) SecurityUtils.getSubject().getSession().getAttribute("verificationCode");
    String phone = (String) SecurityUtils.getSubject().getSession().getAttribute("phone");
    //获取controller传过来的数据
    String verificationCode1 = (String) token.getPrincipal();
    //去数据库根据手机号查询用户信息
    User user = userDao.findUserByUserPhone(phone);
    if (StringUtils.isEmpty(verificationCode)) {
      throw new ServiceException("网络错误");
    }
    //比对手机号
    if (!verificationCode.equals(verificationCode1)) {
      throw new ServiceException("验证码不正确");
    }
    if (user == null) {
      throw new UnknownAccountException();
    }
    if (user.getState() == 0) {
      throw new LockedAccountException();
    }
    return new SimpleAuthenticationInfo(user,phone,getName());
  }
}

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

password为接收的验证码

@PostMapping("verificationCodeLogin")
  @ResponseBody
  public JsonResult verificationCodeLogin(String password) {
    Subject subject = SecurityUtils.getSubject();
    UserPhoneToken token = new UserPhoneToken(password);
    subject.login(token);
    return new JsonResult("login OK");
  }

使用过程中遇到的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();

@Override
  public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
    //这儿的CredentialsMatcher的new的对象必须是AllowAllCredentialsMatcher
    CredentialsMatcher matcher = new AllowAllCredentialsMatcher();
    super.setCredentialsMatcher(matcher);
  }

注解中有一些需要注意的地方,建议看看,注解不对的地方还希望在下放评论指出或者联系我

应为我的知识有限,此方法本人实现目前没有问题,其中有什么不对的地方还希望各位指出,谢谢!

使用的是jdk8,spring boot 的2.2.1版本,shiro的1,.4.1版本

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • shiro之记住登录信息

    Shiro提供了记住我(RememberMe)的功能,比如访问如淘宝等一些网站时,关闭了浏览器下次再打开时还是能记住你是谁,下次访问时无需再登录即可访问,基本流程如下: 1.首先在登录页面选中RememberMe然后登录成功:如果是浏览器登录,一般会把RememberMe的Cookie写到客户端并保存下来: 2.关闭浏览器再重新打开:会发现浏览器还是记住你的: 3.访问一般的网页服务器端还是知道你是谁,且能正常访问: 4.但是比如我们访问淘宝时,如果要查看我的订单或进行支付时,此时还是需要再进行

  • Java中基于Shiro,JWT实现微信小程序登录完整例子及实现过程

    小程序官方流程图如下,官方地址 : https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html : 本文是对接微信小程序自定义登录的一个完整例子实现 ,技术栈为 : SpringBoot+Shiro+JWT+JPA+Redis. 如果对该例子比较感兴趣或者觉得言语表达比较啰嗦,可查看完整的项目地址 : https://github.com/EalenXie/shiro-jwt-applet

  • 关于Apache shiro实现一个账户同一时刻只有一个人登录(shiro 单点登录)

    今天遇到一个项目问题,shiro如何实现一个账户同一时刻只有一session存在的问题,找了几篇文章,在这里就把核心的代码理了理,具体情况如下. 1.假设你使用了Apache shrio ,项目要求一个账户同一时刻只能有一个用户存在,那么你就应该在你的shiro配置文件中添加以下代码: <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.MemorySessionDAO"></

  • Java中SSM+Shiro系统登录验证码的实现方法

     先给大家展示下效果图: 1.验证码生成类: import java.util.Random; import java.awt.image.BufferedImage; import java.awt.Graphics; import java.awt.Font; import java.awt.Color; /** * 验证码生成器类,可生成数字.大写.小写字母及三者混合类型的验证码. 支持自定义验证码字符数量: 支持自定义验证码图片的大小: 支持自定义需排除的特殊字符: * 支持自定义干扰线

  • springmvc+shiro+maven 实现登录认证与权限授权管理

    Shiro 是Shiro 是一个 Apache 下的一开源项目项目,旨在简化身份验证和授权. 1:shiro的配置,通过maven加入shiro相关jar包 <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.1</version> <

  • Shiro 控制并发登录人数限制及登录踢出的实现代码

    我们经常会有用到,当A 用户在北京登录 ,然后A用户在天津再登录 ,要踢出北京登录的状态.如果用户在北京重新登录,那么又要踢出天津的用户,这样反复. 这样保证了一个帐号只能同时一个人使用.那么下面来讲解一下 Shiro  怎么实现这个功能,现在是用到了缓存 Redis  .我们也可以用其他缓存.如果是单个点,直接用一个静态的Map<String,Object> 或者 Ehcache  即可. XML配置. <!-- session 校验单个用户是否多次登录 --> <bean

  • spring boot 集成 shiro 自定义密码验证 自定义freemarker标签根据权限渲染不同页面(推荐

    项目里一直用的是 spring-security ,不得不说,spring-security 真是东西太多了,学习难度太大(可能我比较菜),这篇博客来总结一下折腾shiro的成果,分享给大家,强烈推荐shiro,真心简单 : ) 引入依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4

  • spring boot整合Shiro实现单点登录的示例代码

    Shiro是什么 Shiro是一个Java平台的开源权限框架,用于认证和访问授权.具体来说,满足对如下元素的支持: 用户,角色,权限(仅仅是操作权限,数据权限必须与业务需求紧密结合),资源(url). 用户分配角色,角色定义权限. 访问授权时支持角色或者权限,并且支持多级的权限定义. Q:对组的支持? A:shiro默认不支持对组设置权限. Q:是否可以满足对组进行角色分配的需求? A:扩展Realm,可以支持对组进行分配角色,其实就是给该组下的所有用户分配权限. Q:对数据权限的支持? 在业务

  • shiro多验证登录代码实例及问题解决

    这篇文章主要介绍了shiro多验证登录代码实例及问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1. 首先新建一个shiroConfig shiro的配置类,代码如下: @Configuration是标识这个类是一个配置文件,在启动时会加载这个类里面的内容,这个配置文件的位置的一定一定一定不能防止启动类外面的文件夹中,否则还会在启动类上加注解 @Bean是将这个类交给spring管理 @Configuration public clas

  • springboot整合shiro多验证登录功能的实现(账号密码登录和使用手机验证码登录)

    1. 首先新建一个shiroConfig shiro的配置类,代码如下: @Configuration public class SpringShiroConfig { /** * @param realms 这儿使用接口集合是为了实现多验证登录时使用的 * @return */ @Bean public SecurityManager securityManager(Collection<Realm> realms) { DefaultWebSecurityManager sManager

  • Java实现发送手机短信语音验证功能代码实例

    这篇文章主要介绍了Java实现发送手机短信语音验证功能代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 利用第三方平台可以实现发送手机短信验证码和语音验证码的功能,本文使用框架是struts2+spring+hibernate,现就action层给出核心代码功能. public class VerifyAction extends BaseAction<VerifyRequest> { private static final long

  • Python爬虫实现验证码登录代码实例

    很多网站为了避免被恶意访问,需要设置验证码登录,避免非人类的访问,Python爬虫实现验证码登录的原理则是先到登录页面将生成的验证码保存下来,然后人为输入后,包装后再POST给服务器,实现验证,这里还涉及到了Cookie,其实Cookie保存在本地主机上,避免用户重复输入用户名和密码,在连接服务器的时候将访问连接和Cookie组装起来POST给服务器. 这里涉及到了两次向服务器POST,一次是Cookie,这里还自行设计想要Cookie的内容,由于是要登录,Cookie中存放的则是用户名和密码.

  • Django调用百度AI接口实现人脸注册登录代码实例

    面部识别----考勤打卡.注册登录.面部支付等等...感觉很高大上,又很方便,下面用python中的框架--django完成一个注册登录的功能,调用百度AI的接口,面部识别在网上也有好多教程,可以自己建模,训练模型,但是这都需要大量的数据去提高模型的准确度,我们直接用了百度AI的接口,十分的快捷.高效.准确,下来码一下代码啦!! 首先需要在百度AI官网注册一个应用,免费,并提供强大的人脸库. 1.注册表单 <div class="tab-content"> <div

  • SpringBoot基于Shiro处理ajax请求代码实例

    写一个Shiro的过滤器 import cn.erika.demo.common.model.vo.Message; import com.alibaba.fastjson.JSON; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.servlet.AdviceFilter; import javax.servlet.Servle

  • Kotlin + Spring Boot 请求参数验证的代码实例

    编写 Web 应用程序的时候,经常要做的事就是要对前端传回的数据进行简单的验证,比如是否非空.字符长度是否满足要求,邮箱格式是否正确等等.在 Spring Boot 中,可以使用 Bean Validation (JSR-303) 技术通过注解的方式来进行参数验证. 准备 DTO 对象 data class UserRegisterModel( @get: NotEmpty(message = "User name is required") @get: Size(message =

  • Springboot整合Shiro的代码实例

    这篇文章主要介绍了Springboot整合Shiro的代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.导入依赖 <!--shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</versio

  • Android开发中通过手机号+短信验证码登录的实例代码

    首先,需要一个电话号码,目前很多账户都是将账户名设置成手机号,然后点击按钮获取手机验证码. 其次,你需要后台给你手机短信的验证接口,各个公司用的不一样,这个身为前端,不需要你来考虑,你只要让你后台给你写好接口,你直接调用就好了. activity_login.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.andr

随机推荐