Spring boot Shiro简单的配置与免密码登录

在spring boot中使用Shiro做简单的登陆验证与免密码登陆的写法

  • Spring boot中的配置
    配置自定义ShiroRealm
@Configuration
public class ShiroConfig {
    /**
     * 自定义的Realm
     */
    @Bean(name = "myShiroRealm")
    public ShiroRealm myShiroRealm(HashedCredentialsMatcher matcher){
        ShiroRealm myShiroRealm = new ShiroRealm();
        myShiroRealm.setCredentialsMatcher(matcher);
        return myShiroRealm;
    }

    @Bean
    public SecurityManager securityManager(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm(matcher));
        // 自定义缓存实现 使用redis
        securityManager.setCacheManager(cacheManager());
        // 自定义session管理 使用redis
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 没有登陆的用户只能访问登陆页面
        shiroFilterFactoryBean.setLoginUrl("/page/index/login.html");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/page/index/login.html");
        //自定义拦截器
        Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
        //限制同一帐号同时在线的个数。
        filtersMap.put("kickout", kickoutSessionControlFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);
        return shiroFilterFactoryBean;
    }



    /**
     * 密码匹配凭证管理器
     *
     * @return
     */
    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 采用MD5方式加密
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        // 设置加密次数
        hashedCredentialsMatcher.setHashIterations(Constant.MEGABYTE);
        return hashedCredentialsMatcher;
    }

    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    /**
     * 配置shiro redisManager
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("localhost");
        redisManager.setPort(6379);
        redisManager.setExpire(1800);// 配置缓存过期时间
        redisManager.setTimeout(0);
        // redisManager.setPassword(password);
        return redisManager;
    }

    /**
     * Session Manager
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }

    /**
     * RedisSessionDAO shiro sessionDao层的实现 通过redis
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
     * 限制同一账号登录同时登录人数控制
     *
     * @return
     */
    @Bean
    public KickoutSessionControlFilter kickoutSessionControlFilter() {
        KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
        kickoutSessionControlFilter.setCacheManager(cacheManager());
        kickoutSessionControlFilter.setSessionManager(sessionManager());
        kickoutSessionControlFilter.setKickoutAfter(false);
        kickoutSessionControlFilter.setMaxSession(1);
        /*kickoutSessionControlFilter.setKickoutUrl("/page/index");*/
        return kickoutSessionControlFilter;
    }

    /***
     * 授权所用配置
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
    /***
     * 使授权注解起作用不如不想配置可以在pom文件中加入
     * <dependency>
     *<groupId>org.springframework.boot</groupId>
     *<artifactId>spring-boot-starter-aop</artifactId>
     *</dependency>
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * Shiro生命周期处理器
     *
     */
    @Bean
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
}



public class ShiroRealm extends AuthorizingRealm {


    @Autowired
    UserMapper userMapper;
    @Autowired
    InvokeRedis invokeRedis;

    private AuthenticationInfo info = null;
    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        return authorizationInfo;
    }

    /**
     * 获取登录账号
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       // 将token装换成UsernamePasswordToken
        /*UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;*/
        CustomToken upToken = (CustomToken) authenticationToken;
        // 获取用户名即可
        String username = upToken.getUsername();
        // 查询数据库,是否查询到用户名和密码的用户
        User userInfo = userMapper.selectByUserName(username);
        if(userInfo != null) {
            // 如果查询到了,封装查询结果,返回给我们的调用
            Object principal =  userInfo.getuName();
            Object credentials = userInfo.getuPwd();
            // 获取盐值,即用户名
            ByteSource salt = ByteSource.Util.bytes(userInfo.getuName());
            String realmName = this.getName();
            // 将账户名,密码,盐值,realmName实例化到SimpleAuthenticationInfo中交给Shiro来管理
            info = new SimpleAuthenticationInfo(principal, credentials, salt,realmName);
        }else {
            return null;
        }
        return info;
    }
}

登陆与注册接口

@Override
    public Result<String> login(String username, String password) {
        // 创建Subject实例
        Subject currentUser = SecurityUtils.getSubject();
        // 将用户名及密码封装到UsernamePasswordToken
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            currentUser.login(token);
        } catch ( UnknownAccountException e ) {
            return ResultGenerator.genFailResult("登录失败,用户名不存在");
        } catch ( IncorrectCredentialsException e ) {
            return ResultGenerator.genFailResult("用户名密码错误");
        }
        return ResultGenerator.genSuccessResult("登录成功");
    }

 /**
     * 注册
     * @param username
     * @param password
     * @return
     */
    @Override
    public Result<String> register(String username, String password) {
        //注册接口
        ByteSource salt = ByteSource.Util.bytes(username);
        String newPs = new SimpleHash("MD5", password,salt, Constant.MEGABYTE).toHex();
        User user = new User.Builder().uId(Generate.flowNumber()).uName(username).uPwd(newPs).uStatus(Constant.YES).builder();
        // 看数据库中是否存在该账户
        if(null == userMapper.selectByUserName(username)){
            if(userMapper.insertSelective(user) > 0){
                return ResultGenerator.genSuccessResult("注册成功");
            }
            return ResultGenerator.genFailResult("注册失败");
        }
        return ResultGenerator.genFailResult("注册失败,账号已经被注册");
    }
  • 免密码登陆
    在某些情况只需要验证他的用户信息而不用验证密码,此时会遇到一个问题,当不输入密码登陆时,从数据库查出的密码是最终保存的密码,没有办法通过shiro的密码验证。所以需要重写HashedCredentialsMatcher类中的doCredentialsMatch()与重写UsernamePasswordToken 类,将里面的token换成自定义的token,再将这个自定义token中加入一个标识,来表示是否需要使用密码验证。
public enum  LoginType {
    PASSWORD("password"), // 密码登录
    NOPASSWD("nopassword"); // 免密登录

    private String code;// 状态值

    private LoginType(String code) {
        this.code = code;
    }
    public String getCode () {
        return code;
    }
}


public class CustomToken extends UsernamePasswordToken {
    private static final long serialVersionUID = -2564928913725078138L;

    private LoginType type;


    public CustomToken() {
        super();
    }


    public CustomToken(String username, String password, LoginType type, boolean rememberMe, String host) {
        super(username, password, rememberMe,  host);
        this.type = type;
    }
    /**免密登录*/
    public CustomToken(String username) {
        super(username, "", false, null);
        this.type = LoginType.NOPASSWD;
    }
    /**账号密码登录*/
    public CustomToken(String username, String pwd) {
        super(username, pwd, false, null);
        this.type = LoginType.PASSWORD;
    }

    public LoginType getType() {
        return type;
    }


    public void setType(LoginType type) {
        this.type = type;
    }
}

@Configuration
public class MyRetryLimitCredentialsMatcher extends HashedCredentialsMatcher {

    @Override
    public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
        CustomToken tk = (CustomToken) authcToken;
        if(tk.getType().equals(LoginType.NOPASSWD)){
            return true;
        }
        boolean matches = super.doCredentialsMatch(authcToken, info);
        return matches;
    }


}

还需要修改 ShiroConfig类中的配置文件

/**
     * 自定义的Realm 将参数HashedCredentialsMatcher修改成重写后的类
     */
    @Bean(name = "myShiroRealm")
    public ShiroRealm myShiroRealm(MyRetryLimitCredentialsMatcher matcher){
        ShiroRealm myShiroRealm = new ShiroRealm();
        myShiroRealm.setCredentialsMatcher(matcher);
        return myShiroRealm;
    }
@Bean
    public SecurityManager securityManager(@Qualifier("myRetryLimitCredentialsMatcher") MyRetryLimitCredentialsMatcher matcher){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm(matcher));
        // 自定义缓存实现 使用redis
        securityManager.setCacheManager(cacheManager());
        // 自定义session管理 使用redis
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }
 /**
     * 密码匹配凭证管理器
     *
     * @return
     */
    @Bean(name = "myRetryLimitCredentialsMatcher")
    public MyRetryLimitCredentialsMatcher hashedCredentialsMatcher() {
        MyRetryLimitCredentialsMatcher hashedCredentialsMatcher = new MyRetryLimitCredentialsMatcher();
        // 采用MD5方式加密
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        // 设置加密次数
        hashedCredentialsMatcher.setHashIterations(Constant.MEGABYTE);
        return hashedCredentialsMatcher;
    }

免密码登陆

 @Override
    public Result<String> wxLogin(String weChat) {
        User us = userMapper.selectByUserWXId(weChat);
        if(Verification.isEmpty(us)){
            return ResultGenerator.genFailResult("登录失败,没有绑定手机号");
        }
        // 创建Subject实例
        Subject currentUser = SecurityUtils.getSubject();
        // 将用户名及密码封装到UsernamePasswordToken
        CustomToken token = new CustomToken(us.getuName());
        try {
            currentUser.login(token);
        } catch ( UnknownAccountException e ) {
            return ResultGenerator.genFailResult("登录失败,用户名不存在");
        } catch ( IncorrectCredentialsException e ) {
            return ResultGenerator.genFailResult("用户名密码错误");
        }
        User userInfo = userMapper.selectByUserName(us.getuName());
        integralService.save(userInfo.getuId(),1);
        System.out.println(currentUser.getSession().getId());

        return ResultGenerator.genSuccessResult("登录成功");
    }
  • 12
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值