使用shiro进行登录密码安全验证

使用shiro进行登录密码安全验证

使用框架版本

  • SpringBoot 1.5.3.RELEASE
  • shiro-spring 1.2.5
  • shiro-ehcache 1.2.5

Shiro配置

  • ShiroConfig 中shiroFilter
    /**
     * ShiroFilter
* 注意这里参数中的 StudentService 和 IScoreDao 只是一个例子,因为我们在这里可以用这样的方式获取到相关访问数据库的对象, * 然后读取数据库相关配置,配置到 shiroFilterFactoryBean 的访问规则中。实际项目中,请使用自己的Service来处理业务逻辑。 * * @param securityManager * @return * @author Scan * @create 2017年6月14日 */
@Bean(name = "shiroFilter") public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new MShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/toLogin"); // 登录成功后要跳转的连接 shiroFilterFactoryBean.setSuccessUrl("/back/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); loadShiroFilterChain(shiroFilterFactoryBean); return shiroFilterFactoryBean; }
    /**
     * 加载shiroFilter权限控制规则
     *
     * @author Scan
     * @create  2017年6月14日
     */
    private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean){
        // 下面这些规则配置最好配置到配置文件中
        Map filterChainDefinitionMap = new LinkedHashMap();
        /**
         * authc:该过滤器下的页面必须验证后才能访问,
         * 它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter
         */

        //:这是一个坑呢,一不小心代码就不好使了;
        //


        //配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        /**
         * anon(匿名)  org.apache.shiro.web.filter.authc.AnonymousFilter
         * authc(身份验证)       org.apache.shiro.web.filter.authc.FormAuthenticationFilter
         * authcBasic(http基本验证)    org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
         * logout(退出)        org.apache.shiro.web.filter.authc.LogoutFilter
         * noSessionCreation(不创建session) org.apache.shiro.web.filter.session.NoSessionCreationFilter
         * perms(许可验证)  org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
         * port(端口验证)   org.apache.shiro.web.filter.authz.PortFilter
         * rest  (rest方面)  org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
         * roles(权限验证)  org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
         * ssl (ssl方面)   org.apache.shiro.web.filter.authz.SslFilter
         * member (用户方面)  org.apache.shiro.web.filter.authc.UserFilter
         * user  表示用户不一定已通过认证,只要曾被Shiro记住过登录状态的用户就可以正常发起请求,比如rememberMe
         */
        filterChainDefinitionMap.put("/toLogin", "anon");
        filterChainDefinitionMap.put("/signOut", "logout");
        filterChainDefinitionMap.put("/back/**", "authc");
        filterChainDefinitionMap.put("/**", "anon");  //anon 可以理解为不拦截

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    }

这样我们就可以设置需要拦截的路径,需要注意不要将登录和退出登录的路径进行拦截

  • 编写自己的Realm进行登录验证和授权
public class MyShiroRealm extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);

    @Resource
    private IUserService userService;


    /**
     * 登录认证
     * 身份认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //UsernamePasswordToken对象用来存放提交的登录信息
        UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;

        logger.info("验证当前Subject时获取到token为:" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));

        //查出是否有此用户
        User u = new User();
        u.setUserName(token.getUsername());
        User user = userService.findOne(u);
        if(user!= null){
            // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
            return new SimpleAuthenticationInfo(user.getUserName(), user.getPassWord(),ByteSource.Util.bytes(user.getUserName()),user.getName());
        }
        return null;
    }



    /**
     * 此方法调用  hasRole,hasPermission的时候才会进行回调.
     *
     * 权限信息.(授权):
     * 1、如果用户正常退出,缓存自动清空;
     * 2、如果用户非正常退出,缓存自动清空;
     * 3、如果我们修改了用户的权限,而用户不退出系统,修改的权限无法立即生效。
     * (需要手动编程进行实现;放在service进行调用)
     * 在权限修改后调用realm中的方法,realm已经由spring管理,所以从spring中获取realm实例,
     * 调用clearCached方法;
     * :Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("======================执行Shiro权限认证======================");
        //获取当前登录输入的用户名,等价于(String) principalCollection.fromRealm(getName()).iterator().next();
        String loginName = (String)super.getAvailablePrincipal(principalCollection);
        //到数据库查是否有此对象
        User u = new User();
        u.setUserName(loginName);
        User user = userService.findOne(u);
        // 这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
        if(user == null){
           return null;
        }
        // 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址
        //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        //用户的角色集合
        info.setRoles(user.getRolesName());
        //用户的角色对应的所有权限,如果只使用角色定义访问权限,下面的四行可以不要
        Set roles=user.getRoles();
        for (Role role : roles) {
            info.addStringPermissions(role.getPermissionsName());
        }
      return info;
    }


}
  • LoginController 核心代码 路径 /login
 // 获取当前subject
        Subject currentUser  = SecurityUtils.getSubject();
        // 测试当前的用户是否已经被认证,即是否已经登陆
        // 调用Subject的isAuthenticated
        if (!currentUser.isAuthenticated()) {
            // 把用户名和密码封装为UsernamePasswordToken 对象
            Md5Hash mh = new Md5Hash(validLogin.getPassWord(), validLogin.getUserName(), 3);
            UsernamePasswordToken token = new UsernamePasswordToken(validLogin.getUserName(), mh.toString());
            token.setRememberMe(true);
            try {
                // 执行登陆
                currentUser.login(token);

                // 将当前用户信息放入session
                User u = new User();
                u.setUserName(validLogin.getUserName());
                SecurityUtils.getSubject().getSession().setAttribute("user",userService.findOne(u));

            } catch ( UnknownAccountException e ) {
                System.out.println("用户未注册!");
            } catch ( IncorrectCredentialsException e ) {
                System.out.println("密码错误!!");
            } catch ( LockedAccountException e ) {
                System.out.println("该账户不可用~");
            } catch ( ExcessiveAttemptsException e ) {
                System.out.println("尝试次数超限!!");
            }
        }
  • 登出核心代码 路径 /signOut
 @RequestMapping("signOut")
    public String signOut(HttpServletRequest request){

        Subject currentUser = SecurityUtils.getSubject();
        // 退出登录
        currentUser.logout();

        return "login";
    }

到目前为止使用shiro进行简单的登陆和登出操作就完成了,shiro菜鸟学习记录.

你可能感兴趣的:(Shiro安全框架学,shiro,安全,springboot)